Skip to content

Commit

Permalink
[rtl] minor edits; update to VUnit v5 (#605)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting committed Apr 28, 2023
2 parents 40234cf + 246b6cb commit 0347add
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 111 deletions.
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

0 comments on commit 0347add

Please sign in to comment.