Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rtl] minor edits; update to VUnit v5 #605

Merged
merged 6 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 27.04.2023 | 1.8.4.4 | minor hardware edits and switching activity optimizations of CPU bus unit; [#605](https://github.com/stnolting/neorv32/pull/605) |
| 25.04.2023 | 1.8.4.3 | :bug: fix bug in **DMA** (corrupted write-back when there are bus wait cycles - e.g. when no caches are implemented); [#601](https://github.com/stnolting/neorv32/pull/601) |
| 24.04.2023 | 1.8.4.2 | minor rtl edits; shorten critical path of d-cache setup; [#599](https://github.com/stnolting/neorv32/pull/599) |
| 22.04.2023 | 1.8.4.1 | :sparkles: add optional **direct memory access controller (DMA)**; [#593](https://github.com/stnolting/neorv32/pull/593) |
Expand Down
12 changes: 6 additions & 6 deletions rtl/core/neorv32_cpu.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ entity neorv32_cpu is
d_bus_fence_o : out std_ulogic; -- executed FENCE operation
d_bus_priv_o : out std_ulogic; -- current effective privilege level
-- interrupts --
msw_irq_i : in std_ulogic; -- risc-v: machine software interrupt
mext_irq_i : in std_ulogic; -- risc-v: machine external interrupt
mtime_irq_i : in std_ulogic; -- risc-v: machine timer interrupt
msi_i : in std_ulogic; -- risc-v: machine software interrupt
mei_i : in std_ulogic; -- risc-v: machine external interrupt
mti_i : in std_ulogic; -- risc-v: machine timer interrupt
firq_i : in std_ulogic_vector(15 downto 0); -- custom: fast interrupts
db_halt_req_i : in std_ulogic -- risc-v: halt request (debug mode)
);
Expand Down Expand Up @@ -283,9 +283,9 @@ begin
-- debug mode (halt) request --
db_halt_req_i => db_halt_req_i,
-- interrupts (risc-v compliant) --
msw_irq_i => msw_irq_i, -- machine software interrupt
mext_irq_i => mext_irq_i, -- machine external interrupt
mtime_irq_i => mtime_irq_i, -- machine timer interrupt
msi_i => msi_i, -- machine software interrupt
mei_i => mei_i, -- machine external interrupt
mti_i => mti_i, -- machine timer interrupt
-- fast interrupts (custom) --
firq_i => firq_i, -- fast interrupt trigger
-- physical memory protection --
Expand Down
138 changes: 70 additions & 68 deletions rtl/core/neorv32_cpu_bus.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,14 @@ architecture neorv32_cpu_bus_rtl of neorv32_cpu_bus is
constant pmp_zero_c : std_ulogic_vector(XLEN-1 downto pmp_lsb_c) := (others => '0');

-- misc --
signal data_sign : std_ulogic; -- signed load
signal mar : std_ulogic_vector(XLEN-1 downto 0); -- data memory address register
signal misaligned : std_ulogic; -- misaligned address

-- bus arbiter --
type bus_arbiter_t is record
pend : std_ulogic; -- pending bus access
err : std_ulogic; -- bus access error
pend_rd : std_ulogic; -- pending bus read access
pend_wr : std_ulogic; -- pending bus write access
acc_err : std_ulogic; -- bus access error
pmp_r_err : std_ulogic; -- pmp load fault
pmp_w_err : std_ulogic; -- pmp store fault
end record;
Expand Down Expand Up @@ -139,9 +139,12 @@ begin

-- Access Address -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
mem_adr_reg: process(clk_i)
mem_adr_reg: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
mar <= (others => '0');
misaligned <= '0';
elsif rising_edge(clk_i) then
if (ctrl_i.bus_mo_we = '1') then
mar <= addr_i; -- memory address register
case ctrl_i.ir_funct3(1 downto 0) is -- alignment check
Expand All @@ -161,9 +164,12 @@ begin

-- Write Data: Byte Enable and Alignment --------------------------------------------------
-- -------------------------------------------------------------------------------------------
mem_do_reg: process(clk_i)
mem_do_reg: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
d_bus_wdata_o <= (others => '0');
d_bus_ben_o <= (others => '0');
elsif rising_edge(clk_i) then
if (ctrl_i.bus_mo_we = '1') then
d_bus_ben_o <= (others => '0'); -- default
case ctrl_i.ir_funct3(1 downto 0) is
Expand Down Expand Up @@ -192,91 +198,87 @@ begin

-- Read Data: Alignment and Sign-Extension ------------------------------------------------
-- -------------------------------------------------------------------------------------------
mem_di_reg: process(clk_i)
mem_di_reg: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
case ctrl_i.ir_funct3(1 downto 0) is
when "00" => -- byte
case mar(1 downto 0) is
when "00" => -- byte 0
rdata_o(7 downto 0) <= d_bus_rdata_i(07 downto 00);
rdata_o(XLEN-1 downto 8) <= (others => (data_sign and d_bus_rdata_i(07))); -- sign extension
when "01" => -- byte 1
rdata_o(7 downto 0) <= d_bus_rdata_i(15 downto 08);
rdata_o(XLEN-1 downto 8) <= (others => (data_sign and d_bus_rdata_i(15))); -- sign extension
when "10" => -- byte 2
rdata_o(7 downto 0) <= d_bus_rdata_i(23 downto 16);
rdata_o(XLEN-1 downto 8) <= (others => (data_sign and d_bus_rdata_i(23))); -- sign extension
when others => -- byte 3
rdata_o(7 downto 0) <= d_bus_rdata_i(31 downto 24);
rdata_o(XLEN-1 downto 8) <= (others => (data_sign and d_bus_rdata_i(31))); -- sign extension
end case;
when "01" => -- half-word
if (mar(1) = '0') then
rdata_o(15 downto 0) <= d_bus_rdata_i(15 downto 00); -- low half-word
rdata_o(XLEN-1 downto 16) <= (others => (data_sign and d_bus_rdata_i(15))); -- sign extension
else
rdata_o(15 downto 0) <= d_bus_rdata_i(31 downto 16); -- high half-word
rdata_o(XLEN-1 downto 16) <= (others => (data_sign and d_bus_rdata_i(31))); -- sign extension
end if;
when others => -- word
rdata_o(XLEN-1 downto 0) <= d_bus_rdata_i(XLEN-1 downto 0); -- full word
end case;
if (rstn_i = '0') then
rdata_o <= (others => '0');
elsif rising_edge(clk_i) then
if (arbiter.pend_rd = '1') then -- update only if required (reduce dynamic power)
case ctrl_i.ir_funct3(1 downto 0) is
when "00" => -- byte
case mar(1 downto 0) is
when "00" => -- byte 0
rdata_o(7 downto 0) <= d_bus_rdata_i(07 downto 00);
rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(07))); -- sign-ext
when "01" => -- byte 1
rdata_o(7 downto 0) <= d_bus_rdata_i(15 downto 08);
rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(15))); -- sign-ext
when "10" => -- byte 2
rdata_o(7 downto 0) <= d_bus_rdata_i(23 downto 16);
rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(23))); -- sign-ext
when others => -- byte 3
rdata_o(7 downto 0) <= d_bus_rdata_i(31 downto 24);
rdata_o(XLEN-1 downto 8) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(31))); -- sign-ext
end case;
when "01" => -- half-word
if (mar(1) = '0') then
rdata_o(15 downto 0) <= d_bus_rdata_i(15 downto 00); -- low half-word
rdata_o(XLEN-1 downto 16) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(15))); -- sign-ext
else
rdata_o(15 downto 0) <= d_bus_rdata_i(31 downto 16); -- high half-word
rdata_o(XLEN-1 downto 16) <= (others => ((not ctrl_i.ir_funct3(2)) and d_bus_rdata_i(31))); -- sign-ext
end if;
when others => -- word
rdata_o(XLEN-1 downto 0) <= d_bus_rdata_i(XLEN-1 downto 0); -- full word
end case;
end if;
end if;
end process mem_di_reg;

-- sign extension --
data_sign <= not ctrl_i.ir_funct3(2); -- NOT unsigned LOAD (LBU, LHU)


-- Access Arbiter -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
data_access_arbiter: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
arbiter.pend <= '0';
arbiter.err <= '0';
arbiter.pmp_r_err <= '0';
arbiter.pmp_w_err <= '0';
arbiter.acc_err <= '0';
arbiter.pend_rd <= '0';
arbiter.pend_wr <= '0';
elsif rising_edge(clk_i) then
-- arbiter --
if (arbiter.pend = '0') then -- idle
if (ctrl_i.bus_req = '1') then -- start bus access
arbiter.pend <= '1';
end if;
arbiter.err <= '0';
else -- bus access in progress
-- accumulate bus errors --
if (d_bus_err_i = '1') or -- bus error
((ctrl_i.ir_opcode(5) = '1') and (arbiter.pmp_w_err = '1')) or -- PMP store fault
((ctrl_i.ir_opcode(5) = '0') and (arbiter.pmp_r_err = '1')) then -- PMP load fault
arbiter.err <= '1';
end if;
-- wait for normal termination or start of trap handling --
if (d_bus_ack_i = '1') or (ctrl_i.cpu_trap = '1') then
arbiter.pend <= '0';
end if;
end if;
-- PMP error --
-- PMP error buffer --
if (ctrl_i.bus_mo_we = '1') then -- sample PMP errors only once
arbiter.pmp_r_err <= ld_pmp_fault;
arbiter.pmp_w_err <= st_pmp_fault;
end if;
-- access error buffer --
arbiter.acc_err <= d_bus_err_i or -- bus error
(arbiter.pend_rd and arbiter.pmp_r_err) or -- PMP load fault
(arbiter.pend_wr and arbiter.pmp_w_err); -- PMP store fault
-- arbiter --
if (arbiter.pend_rd = '0') and (arbiter.pend_wr = '0') then -- idle
arbiter.pend_rd <= ctrl_i.bus_req_rd;
arbiter.pend_wr <= ctrl_i.bus_req_wr;
elsif (d_bus_ack_i = '1') or (ctrl_i.cpu_trap = '1') then -- normal termination or start of trap handling
arbiter.pend_rd <= '0';
arbiter.pend_wr <= '0';
end if;
end if;
end process data_access_arbiter;

-- wait for bus response --
d_wait_o <= not d_bus_ack_i;

-- output data access error to control unit --
ma_load_o <= '1' when (arbiter.pend = '1') and (ctrl_i.ir_opcode(5) = '0') and (misaligned = '1') else '0';
be_load_o <= '1' when (arbiter.pend = '1') and (ctrl_i.ir_opcode(5) = '0') and (arbiter.err = '1') else '0';
ma_store_o <= '1' when (arbiter.pend = '1') and (ctrl_i.ir_opcode(5) = '1') and (misaligned = '1') else '0';
be_store_o <= '1' when (arbiter.pend = '1') and (ctrl_i.ir_opcode(5) = '1') and (arbiter.err = '1') else '0';

-- data bus control interface (all source signals are driven by registers) --
d_bus_we_o <= ctrl_i.bus_req and ( ctrl_i.ir_opcode(5)) and (not misaligned) and (not arbiter.pmp_w_err);
d_bus_re_o <= ctrl_i.bus_req and (not ctrl_i.ir_opcode(5)) and (not misaligned) and (not arbiter.pmp_r_err);
ma_load_o <= arbiter.pend_rd and misaligned;
be_load_o <= arbiter.pend_rd and arbiter.acc_err;
ma_store_o <= arbiter.pend_wr and misaligned;
be_store_o <= arbiter.pend_wr and arbiter.acc_err;

-- data bus control interface (all source signals are driven by registers!) --
d_bus_re_o <= ctrl_i.bus_req_rd and (not misaligned) and (not arbiter.pmp_r_err);
d_bus_we_o <= ctrl_i.bus_req_wr and (not misaligned) and (not arbiter.pmp_w_err);
d_bus_fence_o <= ctrl_i.bus_fence;
d_bus_priv_o <= ctrl_i.bus_priv;

Expand Down
45 changes: 24 additions & 21 deletions rtl/core/neorv32_cpu_control.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ entity neorv32_cpu_control is
-- debug mode (halt) request --
db_halt_req_i : in std_ulogic;
-- interrupts (risc-v compliant) --
msw_irq_i : in std_ulogic; -- machine software interrupt
mext_irq_i : in std_ulogic; -- machine external interrupt
mtime_irq_i : in std_ulogic; -- machine timer interrupt
msi_i : in std_ulogic; -- machine software interrupt
mei_i : in std_ulogic; -- machine external interrupt
mti_i : in std_ulogic; -- machine timer interrupt
-- fast interrupts (custom) --
firq_i : in std_ulogic_vector(15 downto 0);
-- physical memory protection --
Expand Down Expand Up @@ -996,10 +996,10 @@ begin
ctrl_nxt.bus_fencei <= '1'; -- FENCE.I
execute_engine.state_nxt <= TRAP_EXECUTE; -- use TRAP_EXECUTE to "modify" PC (PC <= PC)
else
execute_engine.state_nxt <= DISPATCH;
if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then
ctrl_nxt.bus_fence <= '1'; -- FENCE
end if;
execute_engine.state_nxt <= DISPATCH;
end if;


Expand Down Expand Up @@ -1071,19 +1071,21 @@ begin

when MEM_REQ => -- trigger memory request
-- ------------------------------------------------------------
if (trap_ctrl.exc_buf(exc_iillegal_c) = '0') then -- not an illegal instruction
ctrl_nxt.bus_req <= '1'; -- trigger memory request
if (trap_ctrl.exc_buf(exc_iillegal_c) = '1') then -- abort if illegal instruction
execute_engine.state_nxt <= DISPATCH;
else
ctrl_nxt.bus_req_rd <= not execute_engine.ir(5); -- read request
ctrl_nxt.bus_req_wr <= execute_engine.ir(5); -- write request
execute_engine.state_nxt <= MEM_WAIT;
end if;
execute_engine.state_nxt <= MEM_WAIT;


when MEM_WAIT => -- wait for bus transaction to finish
-- ------------------------------------------------------------
ctrl_nxt.rf_mux <= rf_mux_mem_c; -- memory read data
-- wait for memory response --
if ((trap_ctrl.exc_buf(exc_laccess_c) or trap_ctrl.exc_buf(exc_saccess_c) or -- bus access error
trap_ctrl.exc_buf(exc_lalign_c) or trap_ctrl.exc_buf(exc_salign_c) or -- alignment error
trap_ctrl.exc_buf(exc_iillegal_c)) = '1') then -- illegal instruction
if (trap_ctrl.exc_buf(exc_laccess_c) = '1') or (trap_ctrl.exc_buf(exc_saccess_c) = '1') or -- bus access error
(trap_ctrl.exc_buf(exc_lalign_c) = '1') or (trap_ctrl.exc_buf(exc_salign_c) = '1') then -- alignment error
execute_engine.state_nxt <= DISPATCH; -- abort!
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
if (execute_engine.ir(instr_opcode_msb_c-1) = '0') then -- load
Expand Down Expand Up @@ -1147,7 +1149,8 @@ begin
ctrl_o.alu_cp_trig <= ctrl.alu_cp_trig;

-- bus interface --
ctrl_o.bus_req <= ctrl.bus_req;
ctrl_o.bus_req_rd <= ctrl.bus_req_rd;
ctrl_o.bus_req_wr <= ctrl.bus_req_wr;
ctrl_o.bus_mo_we <= ctrl.bus_mo_we;
ctrl_o.bus_fence <= ctrl.bus_fence;
ctrl_o.bus_fencei <= ctrl.bus_fencei;
Expand Down Expand Up @@ -1477,9 +1480,9 @@ begin
-- ----------------------------------------------------------------------

-- RISC-V machine interrupts --
trap_ctrl.irq_pnd(irq_msi_irq_c) <= msw_irq_i;
trap_ctrl.irq_pnd(irq_mei_irq_c) <= mext_irq_i;
trap_ctrl.irq_pnd(irq_mti_irq_c) <= mtime_irq_i;
trap_ctrl.irq_pnd(irq_msi_irq_c) <= msi_i;
trap_ctrl.irq_pnd(irq_mei_irq_c) <= mei_i;
trap_ctrl.irq_pnd(irq_mti_irq_c) <= mti_i;

-- NEORV32-specific fast interrupts --
for i in 0 to 15 loop
Expand Down Expand Up @@ -1528,11 +1531,11 @@ begin
trap_ctrl.wakeup <= '0';
trap_ctrl.env_start <= '0';
elsif rising_edge(clk_i) then
trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf); -- wakeup from sleep due to any pending IRQ (including debug IRQs!)
trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf); -- wakeup from sleep on any pending IRQ (including debug IRQs)
if (trap_ctrl.env_start = '0') then -- no started trap handler yet
-- trigger IRQ only in EXECUTE state to continue execution even on permanent IRQ
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and (execute_engine.state = EXECUTE)) then
trap_ctrl.env_start <= '1'; -- now execute engine can start trap handler
trap_ctrl.env_start <= '1'; -- now execute engine can start trap handling
end if;
else -- trap environment ready to start
if (trap_ctrl.env_start_ack = '1') then -- start of trap handler acknowledged by execute engine
Expand All @@ -1545,7 +1548,7 @@ begin
-- any exception? --
trap_ctrl.exc_fire <= '1' when (or_reduce_f(trap_ctrl.exc_buf) = '1') else '0'; -- sync. exceptions CANNOT be masked

-- valid interrupt request? --
-- any interrupt? --
trap_ctrl.irq_fire <= '1' when
(
(or_reduce_f(trap_ctrl.irq_buf(irq_firq_15_c downto irq_msi_irq_c)) = '1') and -- pending machine IRQ
Expand Down Expand Up @@ -1598,7 +1601,7 @@ begin
elsif (trap_ctrl.irq_buf(irq_firq_15_c) = '1') then trap_ctrl.cause <= trap_firq15_c; -- fast interrupt channel 15
-- standard RISC-V interrupts --
elsif (trap_ctrl.irq_buf(irq_mei_irq_c) = '1') then trap_ctrl.cause <= trap_mei_c; -- machine external interrupt (MEI)
elsif (trap_ctrl.irq_buf(irq_msi_irq_c) = '1') then trap_ctrl.cause <= trap_msi_c; -- machine SW interrupt (MSI)
elsif (trap_ctrl.irq_buf(irq_msi_irq_c) = '1') then trap_ctrl.cause <= trap_msi_c; -- machine software interrupt (MSI)
elsif (trap_ctrl.irq_buf(irq_mti_irq_c) = '1') then trap_ctrl.cause <= trap_mti_c; -- machine timer interrupt (MTI)
else trap_ctrl.cause <= trap_mti_c; end if; -- don't care
end if;
Expand Down Expand Up @@ -2446,9 +2449,9 @@ begin
cnt_event(hpmcnt_event_wait_ii_c) <= '1' when (execute_engine.state = DISPATCH) and (execute_engine.state_prev = DISPATCH) else '0'; -- instruction issue wait cycle
cnt_event(hpmcnt_event_wait_mc_c) <= '1' when (execute_engine.state = ALU_WAIT) else '0'; -- multi-cycle alu-operation wait cycle

cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.bus_req = '1') and (execute_engine.ir(instr_opcode_msb_c-1) = '0') else '0'; -- load operation
cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.bus_req = '1') and (execute_engine.ir(instr_opcode_msb_c-1) = '1') else '0'; -- store operation
cnt_event(hpmcnt_event_wait_ls_c) <= '1' when (execute_engine.state = MEM_WAIT) and (execute_engine.state_prev2 = MEM_WAIT) else '0'; -- load/store memory wait cycle
cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.bus_req_rd = '1') else '0'; -- load operation
cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.bus_req_wr = '1') else '0'; -- store operation
cnt_event(hpmcnt_event_wait_ls_c) <= '1' when (execute_engine.state = MEM_WAIT) and (execute_engine.state_prev2 = MEM_WAIT) else '0'; -- load/store memory wait cycle

cnt_event(hpmcnt_event_jump_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.ir(instr_opcode_lsb_c+2) = '1') else '0'; -- jump (unconditional)
cnt_event(hpmcnt_event_branch_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.ir(instr_opcode_lsb_c+2) = '0') else '0'; -- branch (conditional, taken or not taken)
Expand Down
Loading