diff --git a/CHANGELOG.md b/CHANGELOG.md index 49c38274..844f8473 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date | Version | Comment | Ticket | |:----:|:-------:|:--------|:------:| +| 27.12.2024 | 1.10.8.2 | add out-of-band signals to internal request bus | [#1131](https://github.com/stnolting/neorv32/pull/1131) | | 27.12.2024 | 1.10.8.1 | :warning: replace MTIME by CLINT; :warning: remove `HART_ID` generic | [#1130](https://github.com/stnolting/neorv32/pull/1130) | | 26.12.2024 | [**:rocket:1.10.8**](https://github.com/stnolting/neorv32/releases/tag/v1.10.8) | **New release** | | | 23.12.2024 | 1.10.7.9 | :warning: rework IO/peripheral address space; :sparkles: increase device size from 256 bytes to 64kB | [#1126](https://github.com/stnolting/neorv32/pull/1126) | diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index 7ac2a386..8e469bfe 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -68,8 +68,6 @@ direction as seen from the CPU. 4+^| **Global Signals** | `clk_i` | 1 | in | Global clock line, all registers triggering on rising edge. | `rstn_i` | 1 | in | Global reset, low-active. -| `sleep_o` | 1 | out | CPU is in <<_sleep_mode>> when set. -| `debug_o` | 1 | out | CPU is in <<_cpu_debug_mode,debug mode>> when set. 4+^| **Interrupts (<<_traps_exceptions_and_interrupts>>)** | `msi_i` | 1 | in | RISC-V machine software interrupt. | `mei_i` | 1 | in | RISC-V machine external interrupt. @@ -342,7 +340,7 @@ The `wfi` instruction will raise an illegal instruction exception when executed if `TW` in <<_mstatus>> is set. When executed in debug-mode or during single-stepping `wfi` will behave as simple `nop` without entering sleep mode. -After executing the `wfi` instruction the CPU's `sleep_o` signal (<<_cpu_top_entity_signals>>) will become set +After executing the `wfi` instruction the `sleep` signal of the CPU's request buses (<<_bus_interface>> will become set as soon as the CPU has fully halted: [start=1] @@ -393,15 +391,22 @@ the instruction fetch interface (`i_bus_*` signals) is used for fetching instruc (`d_bus_*` signals) is used to access data via load and store operations. Each of these interfaces can access an address space of up to 2^32^ bytes (4GB). -The bus interface uses two custom interface types: `bus_req_t` is used to propagate the bus access **requests**. These -signals are driven by the _accessing_ device (i.e. the CPU core). `bus_rsp_t` is used to return the bus **response** and -is driven by the _accessed_ device or bus system (i.e. a processor-internal memory or IO device). +The bus interface uses two custom interface types: `bus_req_t` is used to propagate the bus access requests downstream +from a host to a device. These signals are driven by the request-issuing device (i.e. the CPU core). Vice versa, `bus_rsp_t` +is used to return the bus response upstream from a device back to the host and is driven by the accessed device or bus system +(i.e. a processor-internal memory or IO device). + +The signals of the request bus are split in to two categories: _in-band_ signals and _out-of-band_ signals. In-band +signals always belong to a certain bus transaction and are only valid between `stb` being set and the according response +(`err` or `ack`). being set. In contrast, the out-of-band signals are not associated with any bus transaction and are +always valid when set. .Bus Interface - Request Bus (`bus_req_t`) [cols="^1,^1,<6"] [options="header",grid="rows"] |======================= | Signal | Width | Description +3+^| **In-Band Signals** | `addr` | 32 | Access address (byte addressing) | `data` | 32 | Write data | `ben` | 4 | Byte-enable for each byte in `data` @@ -410,7 +415,10 @@ is driven by the _accessed_ device or bus system (i.e. a processor-internal memo | `src` | 1 | Access source (`0` = instruction fetch, `1` = load/store) | `priv` | 1 | Set if privileged (M-mode) access | `rvso` | 1 | Set if current access is a reservation-set operation (`lr` or `sc` instruction, <<_zalrsc_isa_extension>>) -| `fence` | 1 | Data/instruction fence operation; valid without `stb` being set +3+^| **Out-Of-Band Signals** +| `fence` | 1 | Data/instruction fence request; single-shot +| `sleep` | 1 | Set if ALL upstream devices are in <<_sleep_mode>> +| `debug` | 1 | Set if the upstream device is in debug-mode |======================= .Bus Interface - Response Bus (`bus_rsp_t`) @@ -444,7 +452,7 @@ The figure below shows three exemplary bus accesses: . A write access to address `B_addr` writing `wdata` (fastest response; `ACK` arrives right in the next cycle). . A failing read access to address `C_addr` (slow response; `ERR` arrives after several cycles). -.Three Exemplary Bus Transactions +.Three Exemplary Bus Transactions (showing only in-band signals) image::bus_interface.png[700] .Adding Register Stages @@ -478,7 +486,7 @@ and also registers a reservation for the address `addr` (`rvs_valid` becomes set invalidated (`rvs_valid` is `0`) the store access fails, so `wdata2` is **not** written to address `addr` at all. The failed operation is indicated by a **1** being returned via `rsp.data` together with `ack`. -.Three Exemplary LR/SC Bus Transactions +.Three Exemplary LR/SC Bus Transactions (showing only in-band signals) image::bus_interface_atomic.png[700] .Store-Conditional Status diff --git a/docs/figures/bus_interface.png b/docs/figures/bus_interface.png index 2f924812..4ac341cb 100644 Binary files a/docs/figures/bus_interface.png and b/docs/figures/bus_interface.png differ diff --git a/docs/figures/bus_interface_atomic.png b/docs/figures/bus_interface_atomic.png index 370be223..b165f618 100644 Binary files a/docs/figures/bus_interface_atomic.png and b/docs/figures/bus_interface_atomic.png differ diff --git a/docs/sources/bus_interface.json b/docs/sources/bus_interface.json index d6619f8a..e677a799 100644 --- a/docs/sources/bus_interface.json +++ b/docs/sources/bus_interface.json @@ -10,7 +10,6 @@ {name: 'src', wave: 'x0.|.x0.x..|..'}, {name: 'priv', wave: 'x0.|.x0.x..|..'}, {name: 'rvso', wave: 'x0.|.x0.x..|..'}, - {name: 'fence', wave: '0....|.....|..'}, ], {}, [ diff --git a/docs/sources/bus_interface_atomic.json b/docs/sources/bus_interface_atomic.json index 2e91f90d..6704900d 100644 --- a/docs/sources/bus_interface_atomic.json +++ b/docs/sources/bus_interface_atomic.json @@ -10,7 +10,6 @@ {name: 'src', wave: '0....|.....|.....'}, {name: 'priv', wave: '0....|.....|.....'}, {name: 'rvso', wave: '01..0|.1..0|.1..0', node: '.b.......e....'}, - {name: 'fence', wave: '0....|.....|.....'}, ], {}, [ diff --git a/rtl/core/neorv32_bus.vhd b/rtl/core/neorv32_bus.vhd index 7c681cd6..bf03d922 100644 --- a/rtl/core/neorv32_bus.vhd +++ b/rtl/core/neorv32_bus.vhd @@ -19,14 +19,15 @@ use neorv32.neorv32_package.all; entity neorv32_bus_switch is generic ( - PORT_A_READ_ONLY : boolean; -- set if port A is read-only - PORT_B_READ_ONLY : boolean -- set if port B is read-only + ROUND_ROBIN_EN : boolean := false; -- enable round-robing scheduling + PORT_A_READ_ONLY : boolean := false; -- set if port A is read-only + PORT_B_READ_ONLY : boolean := false -- set if port B is read-only ); port ( clk_i : in std_ulogic; -- global clock, rising edge rstn_i : in std_ulogic; -- global reset, low-active, async a_lock_i : in std_ulogic; -- exclusive access for port A while set - a_req_i : in bus_req_t; -- host port A request bus (PRIORITIZED) + a_req_i : in bus_req_t; -- host port A request bus a_rsp_o : out bus_rsp_t; -- host port A response bus b_req_i : in bus_req_t; -- host port B request bus b_rsp_o : out bus_rsp_t; -- host port B response bus @@ -38,17 +39,10 @@ end neorv32_bus_switch; architecture neorv32_bus_switch_rtl of neorv32_bus_switch is -- access arbiter -- - type arbiter_t is record - state, state_nxt : std_ulogic_vector(1 downto 0); - a_req, b_req : std_ulogic; - sel, stb : std_ulogic; - end record; - signal arbiter : arbiter_t; - - -- FSM states -- - constant IDLE : std_ulogic_vector(1 downto 0) := "00"; - constant BUSY_A : std_ulogic_vector(1 downto 0) := "01"; - constant BUSY_B : std_ulogic_vector(1 downto 0) := "10"; + type state_t is (S_CHECK_A, S_BUSY_A, S_CHECK_B, S_BUSY_B); + signal state, state_nxt : state_t; + signal a_req, b_req : std_ulogic; + signal sel, stb : std_ulogic; begin @@ -57,86 +51,158 @@ begin arbiter_sync: process(rstn_i, clk_i) begin if (rstn_i = '0') then - arbiter.state <= IDLE; - arbiter.a_req <= '0'; - arbiter.b_req <= '0'; + state <= S_CHECK_A; + a_req <= '0'; + b_req <= '0'; elsif rising_edge(clk_i) then - arbiter.state <= arbiter.state_nxt; - arbiter.a_req <= (arbiter.a_req or a_req_i.stb) and (not arbiter.state(0)); -- clear STB buffer in BUSY_A - arbiter.b_req <= (arbiter.b_req or b_req_i.stb) and (not arbiter.state(1)); -- clear STB buffer in BUSY_B + state <= state_nxt; + if (state = S_BUSY_A) then -- clear request + a_req <= '0'; + else -- buffer request + a_req <= a_req or a_req_i.stb; + end if; + if (state = S_BUSY_B) then -- clear request + b_req <= '0'; + else -- buffer request + b_req <= b_req or b_req_i.stb; + end if; end if; end process arbiter_sync; - -- fsm -- - arbiter_comb: process(arbiter, a_lock_i, a_req_i, b_req_i, x_rsp_i) - begin - -- defaults -- - arbiter.state_nxt <= arbiter.state; - arbiter.sel <= '0'; - arbiter.stb <= '0'; - -- state machine -- - case arbiter.state is + -- Prioritizing Bus Switch ---------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + arbiter_prioritized: + if not ROUND_ROBIN_EN generate + arbiter_fsm: process(state, a_req, b_req, a_lock_i, a_req_i, b_req_i, x_rsp_i) + begin + -- defaults -- + state_nxt <= state; + sel <= '0'; + stb <= '0'; - when BUSY_A => -- port A access in progress - -- ------------------------------------------------------------ - arbiter.sel <= '0'; - if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then - arbiter.state_nxt <= IDLE; - end if; + -- state machine -- + case state is - when BUSY_B => -- port B access in progress - -- ------------------------------------------------------------ - arbiter.sel <= '1'; - if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then - arbiter.state_nxt <= IDLE; - end if; + when S_BUSY_A => -- port A access in progress + -- ------------------------------------------------------------ + sel <= '0'; + if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then + state_nxt <= S_CHECK_A; + end if; - when others => -- IDLE: wait for requests - -- ------------------------------------------------------------ - if (a_req_i.stb = '1') or (arbiter.a_req = '1') then -- request from port A (prioritized)? - arbiter.sel <= '0'; - arbiter.stb <= '1'; - arbiter.state_nxt <= BUSY_A; - elsif ((b_req_i.stb = '1') or (arbiter.b_req = '1')) and (a_lock_i = '0') then -- request from port B? - arbiter.sel <= '1'; - arbiter.stb <= '1'; - arbiter.state_nxt <= BUSY_B; - end if; + when S_BUSY_B => -- port B access in progress + -- ------------------------------------------------------------ + sel <= '1'; + if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then + state_nxt <= S_CHECK_A; + end if; - end case; - end process arbiter_comb; + when others => -- wait for requests + -- ------------------------------------------------------------ + if (a_req_i.stb = '1') or (a_req = '1') then -- request from port A (prioritized)? + sel <= '0'; + stb <= '1'; + state_nxt <= S_BUSY_A; + elsif ((b_req_i.stb = '1') or (b_req = '1')) and (a_lock_i = '0') then -- request from port B? + sel <= '1'; + stb <= '1'; + state_nxt <= S_BUSY_B; + end if; + + end case; + end process arbiter_fsm; + end generate; + + + -- Round-Robin Arbiter -------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + arbiter_round_robin: + if ROUND_ROBIN_EN generate + arbiter_fsm: process(state, a_req, b_req, a_req_i, b_req_i, x_rsp_i) + begin + -- defaults -- + state_nxt <= state; + sel <= '0'; + stb <= '0'; + + -- state machine -- + case state is + + when S_CHECK_A => -- check if access from port A + -- ------------------------------------------------------------ + sel <= '0'; + if (a_req_i.stb = '1') or (a_req = '1') then + stb <= '1'; + state_nxt <= S_BUSY_A; + else + state_nxt <= S_CHECK_B; + end if; + + when S_BUSY_A => -- port B access in progress + -- ------------------------------------------------------------ + sel <= '0'; + if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then + state_nxt <= S_CHECK_B; + end if; + + when S_CHECK_B => -- check if access from port B + -- ------------------------------------------------------------ + sel <= '1'; + if (b_req_i.stb = '1') or (b_req = '1') then + stb <= '1'; + state_nxt <= S_BUSY_B; + else + state_nxt <= S_CHECK_A; + end if; + + when S_BUSY_B => -- port B access in progress + -- ------------------------------------------------------------ + sel <= '1'; + if (x_rsp_i.err = '1') or (x_rsp_i.ack = '1') then + state_nxt <= S_CHECK_A; + end if; + + when others => -- undefined + -- ------------------------------------------------------------ + state_nxt <= S_CHECK_A; + + end case; + end process arbiter_fsm; + end generate; -- Request Switch ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - x_req_o.addr <= a_req_i.addr when (arbiter.sel = '0') else b_req_i.addr; - x_req_o.rvso <= a_req_i.rvso when (arbiter.sel = '0') else b_req_i.rvso; - x_req_o.priv <= a_req_i.priv when (arbiter.sel = '0') else b_req_i.priv; - x_req_o.src <= a_req_i.src when (arbiter.sel = '0') else b_req_i.src; - x_req_o.rw <= a_req_i.rw when (arbiter.sel = '0') else b_req_i.rw; - x_req_o.fence <= a_req_i.fence or b_req_i.fence; -- propagate any fence operations + x_req_o.addr <= a_req_i.addr when (sel = '0') else b_req_i.addr; + x_req_o.rvso <= a_req_i.rvso when (sel = '0') else b_req_i.rvso; + x_req_o.priv <= a_req_i.priv when (sel = '0') else b_req_i.priv; + x_req_o.src <= a_req_i.src when (sel = '0') else b_req_i.src; + x_req_o.rw <= a_req_i.rw when (sel = '0') else b_req_i.rw; + x_req_o.fence <= a_req_i.fence or b_req_i.fence; -- propagate any fence request + x_req_o.sleep <= a_req_i.sleep and b_req_i.sleep; -- set if ALL upstream devices are in sleep mode + x_req_o.debug <= a_req_i.debug when (sel = '0') else b_req_i.debug; - x_req_o.data <= b_req_i.data when PORT_A_READ_ONLY else - a_req_i.data when PORT_B_READ_ONLY else - a_req_i.data when (arbiter.sel = '0') else b_req_i.data; + x_req_o.data <= b_req_i.data when PORT_A_READ_ONLY else + a_req_i.data when PORT_B_READ_ONLY else + a_req_i.data when (sel = '0') else b_req_i.data; - x_req_o.ben <= b_req_i.ben when PORT_A_READ_ONLY else - a_req_i.ben when PORT_B_READ_ONLY else - a_req_i.ben when (arbiter.sel = '0') else b_req_i.ben; + x_req_o.ben <= b_req_i.ben when PORT_A_READ_ONLY else + a_req_i.ben when PORT_B_READ_ONLY else + a_req_i.ben when (sel = '0') else b_req_i.ben; - x_req_o.stb <= arbiter.stb; + x_req_o.stb <= stb; -- Response Switch ------------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- a_rsp_o.data <= x_rsp_i.data; - a_rsp_o.ack <= x_rsp_i.ack when (arbiter.sel = '0') else '0'; - a_rsp_o.err <= x_rsp_i.err when (arbiter.sel = '0') else '0'; + a_rsp_o.ack <= x_rsp_i.ack when (sel = '0') else '0'; + a_rsp_o.err <= x_rsp_i.err when (sel = '0') else '0'; b_rsp_o.data <= x_rsp_i.data; - b_rsp_o.ack <= x_rsp_i.ack when (arbiter.sel = '1') else '0'; - b_rsp_o.err <= x_rsp_i.err when (arbiter.sel = '1') else '0'; + b_rsp_o.ack <= x_rsp_i.ack when (sel = '1') else '0'; + b_rsp_o.err <= x_rsp_i.err when (sel = '1') else '0'; end neorv32_bus_switch_rtl; @@ -703,10 +769,10 @@ entity neorv32_bus_reservation_set is rvs_addr_o : out std_ulogic_vector(31 downto 0); rvs_valid_o : out std_ulogic; rvs_clear_i : in std_ulogic; - -- core/cpu port -- + -- core port -- core_req_i : in bus_req_t; core_rsp_o : out bus_rsp_t; - -- system ports -- + -- system port -- sys_req_o : out bus_req_t; sys_rsp_i : in bus_rsp_t ); diff --git a/rtl/core/neorv32_cache.vhd b/rtl/core/neorv32_cache.vhd index 86164e6b..2ba83dc3 100644 --- a/rtl/core/neorv32_cache.vhd +++ b/rtl/core/neorv32_cache.vhd @@ -183,7 +183,7 @@ begin -- request splitter: cached or direct access -- req_splitter: process(host_req_i, dir_acc_d) begin - -- default: pass-through of all bus signals -- + -- default: pass-through all bus signals -- cache_req <= host_req_i; dir_req_d <= host_req_i; -- direct access -- @@ -826,7 +826,7 @@ begin -- Control Engine FSM Comb ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - ctrl_engine_comb: process(state, upret, addr, haddr, baddr, bus_rsp_i, cmd_sync_i, cmd_miss_i, rdata_i, dirty_i) + ctrl_engine_comb: process(state, upret, addr, haddr, baddr, host_req_i, bus_rsp_i, cmd_sync_i, cmd_miss_i, rdata_i, dirty_i) begin -- control engine defaults -- state_nxt <= state; @@ -845,13 +845,19 @@ begin new_o <= '0'; -- bus interface defaults -- - bus_req_o <= req_terminate_c; -- all-zero - bus_req_o.addr <= addr.tag & addr.idx & addr.ofs & "00"; -- always word-aligned - bus_req_o.data <= rdata_i; - bus_req_o.ben <= (others => '1'); -- full-word writes only - bus_req_o.src <= '0'; -- cache accesses are always "data" accesses - bus_req_o.priv <= '0'; -- cache accesses are always "unprivileged" accesses - bus_req_o.rvso <= '0'; -- cache accesses can never be a reservation set operation + bus_req_o <= req_terminate_c; -- all-zero + bus_req_o.addr <= addr.tag & addr.idx & addr.ofs & "00"; -- always word-aligned + bus_req_o.data <= rdata_i; + bus_req_o.ben <= (others => '1'); -- full-word writes only + bus_req_o.src <= '0'; -- cache accesses are always data accesses + bus_req_o.priv <= '0'; -- cache accesses are always "unprivileged" accesses + bus_req_o.rvso <= '0'; -- cache accesses can never be a reservation set operation + bus_req_o.debug <= host_req_i.debug; + if (state = S_IDLE) then + bus_req_o.sleep <= host_req_i.sleep; + else + bus_req_o.sleep <= '0'; + end if; -- fsm -- case state is diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd index 1c941c6b..ee6f4903 100644 --- a/rtl/core/neorv32_cpu.vhd +++ b/rtl/core/neorv32_cpu.vhd @@ -71,8 +71,6 @@ entity neorv32_cpu is -- global control -- clk_i : in std_ulogic; -- switchable global clock, rising edge rstn_i : in std_ulogic; -- global reset, low-active, async - sleep_o : out std_ulogic; -- cpu is in sleep mode when set - debug_o : out std_ulogic; -- cpu is in debug mode when set -- interrupts -- msi_i : in std_ulogic; -- risc-v machine software interrupt mei_i : in std_ulogic; -- risc-v machine external interrupt @@ -290,10 +288,6 @@ begin -- external CSR read-back -- xcsr_rdata_res <= xcsr_rdata_pmp or xcsr_rdata_alu; - -- CPU state -- - sleep_o <= ctrl.cpu_sleep; - debug_o <= ctrl.cpu_debug; - -- Register File -------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index 2706194d..1ddfaf71 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -362,7 +362,7 @@ begin ((fetch_engine.pc(1) = '0') or (not RISCV_ISA_C)) else '0'; ipb.we(1) <= '1' when (fetch_engine.state = IF_PENDING) and (fetch_engine.resp = '1') else '0'; - -- bus access type -- + -- bus access meta data -- ibus_req_o.priv <= fetch_engine.priv; -- current effective privilege level ibus_req_o.data <= (others => '0'); -- read-only ibus_req_o.ben <= (others => '0'); -- read-only @@ -370,6 +370,8 @@ begin ibus_req_o.src <= '1'; -- source = instruction fetch ibus_req_o.rvso <= '0'; -- cannot be a reservation set operation ibus_req_o.fence <= ctrl.lsu_fence; -- fence operation, valid without STB being set + ibus_req_o.sleep <= sleep_mode; -- sleep mode, valid without STB being set + ibus_req_o.debug <= debug_ctrl.run; -- debug mode, valid without STB being set -- Instruction Prefetch Buffer (FIFO) ----------------------------------------------------- diff --git a/rtl/core/neorv32_cpu_lsu.vhd b/rtl/core/neorv32_cpu_lsu.vhd index 5278f887..f45580fc 100644 --- a/rtl/core/neorv32_cpu_lsu.vhd +++ b/rtl/core/neorv32_cpu_lsu.vhd @@ -106,7 +106,9 @@ begin end process mem_do_reg; dbus_req_o.src <= '0'; -- 0 = data access - dbus_req_o.fence <= ctrl_i.lsu_fence; -- this is valid without STB being set + dbus_req_o.fence <= ctrl_i.lsu_fence; -- out-of-band: this is valid without STB being set + dbus_req_o.sleep <= ctrl_i.cpu_sleep; -- out-of-band: this is valid without STB being set + dbus_req_o.debug <= ctrl_i.cpu_debug; -- out-of-band: this is valid without STB being set -- Data Input: Alignment and Sign-Extension ----------------------------------------------- diff --git a/rtl/core/neorv32_debug_dm.vhd b/rtl/core/neorv32_debug_dm.vhd index 12278292..af2d70b8 100644 --- a/rtl/core/neorv32_debug_dm.vhd +++ b/rtl/core/neorv32_debug_dm.vhd @@ -25,7 +25,6 @@ entity neorv32_debug_dm is -- global control -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - cpu_debug_i : in std_ulogic; -- CPU is in debug mode -- debug module interface (DMI) -- dmi_req_i : in dmi_req_t; -- request dmi_rsp_o : out dmi_rsp_t; -- response @@ -69,6 +68,7 @@ architecture neorv32_debug_dm_rtl of neorv32_debug_dm is constant addr_progbuf1_c : std_ulogic_vector(6 downto 0) := "0100001"; constant addr_authdata_c : std_ulogic_vector(6 downto 0) := "0110000"; --constant addr_sbcs_c : std_ulogic_vector(6 downto 0) := "0111000"; -- hardwired to zero + constant addr_haltsum0_c : std_ulogic_vector(6 downto 0) := "1000000"; -- DMI access -- signal dmi_wren, dmi_wren_auth, dmi_rden, dmi_rden_auth : std_ulogic; @@ -666,7 +666,7 @@ begin end process bus_access; -- access helpers -- - accen <= cpu_debug_i and bus_req_i.stb; -- allow access only when in debug-mode + accen <= bus_req_i.debug and bus_req_i.stb; -- allow access only when in debug-mode rden <= accen and (not bus_req_i.rw); wren <= accen and ( bus_req_i.rw); diff --git a/rtl/core/neorv32_dma.vhd b/rtl/core/neorv32_dma.vhd index afc569d5..f362059a 100644 --- a/rtl/core/neorv32_dma.vhd +++ b/rtl/core/neorv32_dma.vhd @@ -310,6 +310,8 @@ begin dma_req_o.addr <= engine.src_addr when (engine.state = S_READ) else engine.dst_addr; dma_req_o.rvso <= '0'; -- no reservation set operation possible dma_req_o.fence <= cfg.enable and cfg.fence and engine.done; -- issue FENCE operation when transfer is done + dma_req_o.sleep <= '1' when (engine.state = S_IDLE) else '0'; -- idle = sleep mode + dma_req_o.debug <= '0'; -- can never ever be in debug mode -- address increment -- address_inc: process(cfg.qsel) diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index af44db6f..d2ff396b 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -29,7 +29,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100801"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100802"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width @@ -129,7 +129,10 @@ package neorv32_package is src : std_ulogic; -- access source (1=instruction fetch, 0=data access) priv : std_ulogic; -- set if privileged (machine-mode) access rvso : std_ulogic; -- set if reservation set operation (atomic LR/SC) - fence : std_ulogic; -- set if fence(.i) operation, single-shot (out-of-band) + -- out-of-band signals -- + fence : std_ulogic; -- set if fence(.i) request by upstream device, single-shot + sleep : std_ulogic; -- set if ALL upstream sources are in sleep mode + debug : std_ulogic; -- set if upstream device is in debug mode end record; -- bus response -- @@ -149,7 +152,9 @@ package neorv32_package is src => '0', priv => '0', rvso => '0', - fence => '0' + fence => '0', + sleep => '1', + debug => '0' ); -- endpoint (response) termination -- diff --git a/rtl/core/neorv32_sysinfo.vhd b/rtl/core/neorv32_sysinfo.vhd index 72f97fb7..65f5003b 100644 --- a/rtl/core/neorv32_sysinfo.vhd +++ b/rtl/core/neorv32_sysinfo.vhd @@ -103,7 +103,7 @@ begin end if; end process sysinfo_0_write; - -- SYSINFO(1): Internal Memory Configuration (sizes) + -- SYSINFO(1): Misc -- sysinfo(1)(7 downto 0) <= std_ulogic_vector(to_unsigned(index_size_f(MEM_INT_IMEM_SIZE), 8)); -- log2(IMEM size) sysinfo(1)(15 downto 8) <= std_ulogic_vector(to_unsigned(index_size_f(MEM_INT_DMEM_SIZE), 8)); -- log2(DMEM size) sysinfo(1)(23 downto 16) <= (others => '0'); -- reserved diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index 70759848..f26ed825 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -298,9 +298,6 @@ architecture neorv32_top_rtl of neorv32_top is signal clk_gen_en : clk_gen_en_t; signal clk_gen_en2 : std_ulogic_vector(11 downto 0); - -- CPU status -- - signal cpu_debug, cpu_sleep : std_ulogic; - -- debug module interface (DMI) -- signal dmi_req : dmi_req_t; signal dmi_rsp : dmi_rsp_t; @@ -459,6 +456,26 @@ begin -- ************************************************************************************************************************** -- Core Complex -- ************************************************************************************************************************** + + -- fast interrupt requests (FIRQs) -- + cpu_firq(0) <= firq(FIRQ_TWD); + cpu_firq(1) <= firq(FIRQ_CFS); + cpu_firq(2) <= firq(FIRQ_UART0_RX); + cpu_firq(3) <= firq(FIRQ_UART0_TX); + cpu_firq(4) <= firq(FIRQ_UART1_RX); + cpu_firq(5) <= firq(FIRQ_UART1_TX); + cpu_firq(6) <= firq(FIRQ_SPI); + cpu_firq(7) <= firq(FIRQ_TWI); + cpu_firq(8) <= firq(FIRQ_XIRQ); + cpu_firq(9) <= firq(FIRQ_NEOLED); + cpu_firq(10) <= firq(FIRQ_DMA); + cpu_firq(11) <= firq(FIRQ_SDI); + cpu_firq(12) <= firq(FIRQ_GPTMR); + cpu_firq(13) <= firq(FIRQ_ONEWIRE); + cpu_firq(14) <= firq(FIRQ_SLINK_RX); + cpu_firq(15) <= firq(FIRQ_SLINK_TX); + + -- CPU core + optional L1 caches -- core_complex: if true generate @@ -516,8 +533,6 @@ begin -- global control -- clk_i => clk_i, rstn_i => rstn_sys, - sleep_o => cpu_sleep, - debug_o => cpu_debug, -- interrupts -- msi_i => msw_irq, mei_i => mext_irq_i, @@ -532,26 +547,8 @@ begin dbus_rsp_i => cpu_d_rsp ); - -- fast interrupt requests (FIRQs) -- - cpu_firq(0) <= firq(FIRQ_TWD); - cpu_firq(1) <= firq(FIRQ_CFS); - cpu_firq(2) <= firq(FIRQ_UART0_RX); - cpu_firq(3) <= firq(FIRQ_UART0_TX); - cpu_firq(4) <= firq(FIRQ_UART1_RX); - cpu_firq(5) <= firq(FIRQ_UART1_TX); - cpu_firq(6) <= firq(FIRQ_SPI); - cpu_firq(7) <= firq(FIRQ_TWI); - cpu_firq(8) <= firq(FIRQ_XIRQ); - cpu_firq(9) <= firq(FIRQ_NEOLED); - cpu_firq(10) <= firq(FIRQ_DMA); - cpu_firq(11) <= firq(FIRQ_SDI); - cpu_firq(12) <= firq(FIRQ_GPTMR); - cpu_firq(13) <= firq(FIRQ_ONEWIRE); - cpu_firq(14) <= firq(FIRQ_SLINK_RX); - cpu_firq(15) <= firq(FIRQ_SLINK_TX); - - -- CPU Instruction Cache (I-Cache) -------------------------------------------------------- + -- CPU L1 Instruction Cache (I-Cache) ----------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_icache_inst_true: if ICACHE_EN generate @@ -580,7 +577,7 @@ begin end generate; - -- CPU Data Cache (D-Cache) --------------------------------------------------------------- + -- CPU L1 Data Cache (D-Cache) ------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_dcache_inst_true: if DCACHE_EN generate @@ -613,13 +610,14 @@ begin -- ------------------------------------------------------------------------------------------- neorv32_core_bus_switch_inst: entity neorv32.neorv32_bus_switch generic map ( + ROUND_ROBIN_EN => false, -- use prioritizing arbitration PORT_A_READ_ONLY => false, PORT_B_READ_ONLY => true -- i-fetch is read-only ) port map ( clk_i => clk_i, rstn_i => rstn_sys, - a_lock_i => '0', -- no exclusive accesses for port A + a_lock_i => '0', -- no exclusive accesses a_req_i => dcache_req, -- prioritized a_rsp_o => dcache_rsp, b_req_i => icache_req, @@ -656,13 +654,14 @@ begin -- ------------------------------------------------------------------------------------------- neorv32_dma_bus_switch_inst: entity neorv32.neorv32_bus_switch generic map ( + ROUND_ROBIN_EN => false, -- use prioritizing arbitration PORT_A_READ_ONLY => false, PORT_B_READ_ONLY => false ) port map ( clk_i => clk_i, rstn_i => rstn_sys, - a_lock_i => '0', -- no exclusive accesses for port A + a_lock_i => '0', -- no exclusive accesses a_req_i => core_req, -- prioritized a_rsp_o => core_rsp, b_req_i => dma_req, @@ -1151,8 +1150,6 @@ begin rstn_sys_i => rstn_sys, bus_req_i => iodev_req(IODEV_WDT), bus_rsp_o => iodev_rsp(IODEV_WDT), - cpu_debug_i => cpu_debug, - cpu_sleep_i => cpu_sleep, clkgen_en_o => clk_gen_en(CG_WDT), clkgen_i => clk_gen, rstn_o => rstn_wdt @@ -1690,7 +1687,6 @@ begin port map ( clk_i => clk_i, rstn_i => rstn_ext, - cpu_debug_i => cpu_debug, dmi_req_i => dmi_req, dmi_rsp_o => dmi_rsp, bus_req_i => iodev_req(IODEV_OCD), diff --git a/rtl/core/neorv32_wdt.vhd b/rtl/core/neorv32_wdt.vhd index 794c4cd2..b4827bc6 100644 --- a/rtl/core/neorv32_wdt.vhd +++ b/rtl/core/neorv32_wdt.vhd @@ -23,8 +23,6 @@ entity neorv32_wdt is rstn_sys_i : in std_ulogic; -- system reset, low-active bus_req_i : in bus_req_t; -- bus request bus_rsp_o : out bus_rsp_t; -- bus response - cpu_debug_i : in std_ulogic; -- CPU is in debug mode - cpu_sleep_i : in std_ulogic; -- CPU is in sleep mode clkgen_en_o : out std_ulogic; -- enable clock generator clkgen_i : in std_ulogic_vector(7 downto 0); rstn_o : out std_ulogic -- timeout reset, low_active, sync @@ -155,8 +153,8 @@ begin -- valid counter increment? -- cnt_inc <= '1' when ((prsc_tick = '1') and (cnt_started = '1')) and -- clock tick and started - ((cpu_debug_i = '0') or (ctrl.dben = '1')) and -- not in debug mode or allowed to run in debug mode - ((cpu_sleep_i = '0') or (ctrl.sen = '1')) else '0'; -- not in sleep mode or allowed to run in sleep mode + ((bus_req_i.debug = '0') or (ctrl.dben = '1')) and -- not in debug mode or allowed to run in debug mode + ((bus_req_i.sleep = '0') or (ctrl.sen = '1')) else '0'; -- not in sleep mode or allowed to run in sleep mode -- timeout detector -- cnt_timeout <= '1' when (cnt_started = '1') and (cnt = ctrl.timeout) else '0';