mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 14:17:51 -04:00
Add "out-of-band" signals to internal bus interface (#1131)
This commit is contained in:
commit
a4935d249f
17 changed files with 219 additions and 141 deletions
|
@ -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) |
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 52 KiB |
Binary file not shown.
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 57 KiB |
|
@ -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....|.....|..'},
|
||||
],
|
||||
{},
|
||||
[
|
||||
|
|
|
@ -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....|.....|.....'},
|
||||
],
|
||||
{},
|
||||
[
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -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) -----------------------------------------------------
|
||||
|
|
|
@ -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 -----------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 --
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue