Skip to content

Commit

Permalink
Add SLINK routing information ports (#908)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting committed May 22, 2024
2 parents 6f9abc9 + d36ba07 commit c5dd617
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 57 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 21.05.2024 | 1.9.9.2 | :sparkles: add SLINK routing information ports (compatible to AXI-stream's `TID` and `TDEST` signals) | [#908](https://github.com/stnolting/neorv32/pull/908) |
| 04.05.2024 | 1.9.9.1 | :sparkles: add NEORV32 as Vivado IP block | [#894](https://github.com/stnolting/neorv32/pull/894) |
| 03.05.2024 | [**:rocket:1.9.9**](https://github.com/stnolting/neorv32/releases/tag/v1.9.9) | **New release** | |
| 02.05.2024 | 1.9.8.10 | :bug: fix UART receiver bug (introduced in v1.9.8.7) | [#891](https://github.com/stnolting/neorv32/pull/891) |
Expand Down
2 changes: 2 additions & 0 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,12 @@ Some interfaces (like the TWI and the 1-Wire bus) require tri-state drivers in t
| `xbus_err_i` | 1 | in | `'L'` | transfer error
5+^| **<<_stream_link_interface_slink>>**
| `slink_rx_dat_i` | 32 | in | `'L'` | RX data
| `slink_rx_src_i` | 4 | in | `'L'` | RX source routing information
| `slink_rx_val_i` | 1 | in | `'L'` | RX data valid
| `slink_rx_lst_i` | 1 | in | `'L'` | RX last element of stream
| `slink_rx_rdy_o` | 1 | out | - | RX ready to receive
| `slink_tx_dat_o` | 32 | out | - | TX data
| `slink_tx_dst_o` | 4 | out | - | TX destination routing information
| `slink_tx_val_o` | 1 | out | - | TX data valid
| `slink_tx_lst_o` | 1 | out | - | TX last element of stream
| `slink_tx_rdy_i` | 1 | in | `'L'` | TX allowed to send
Expand Down
19 changes: 17 additions & 2 deletions docs/datasheet/soc_slink.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
| Software driver files: | neorv32_slink.c |
| | neorv32_slink.h |
| Top entity ports: | `slink_rx_dat_i` | RX link data (32-bit)
| | `slink_rx_src_i` | RX routing information (4-bit)
| | `slink_rx_val_i` | RX link data valid (1-bit)
| | `slink_rx_lst_i` | RX link last element of stream (1-bit)
| | `slink_rx_rdy_o` | RX link ready to receive (1-bit)
| | `slink_tx_dat_o` | TX link data (32-bit)
| | `slink_tx_dst_o` | TX routing information (4-bit)
| | `slink_tx_val_o` | TX link data valid (1-bit)
| | `slink_tx_lst_o` | TX link last element of stream (1-bit)
| | `slink_tx_rdy_i` | TX link allowed to send (1-bit)
Expand Down Expand Up @@ -45,10 +47,11 @@ The SLINK interface consists of four signals for each channel:
* `val` marks the current transmission cycle as valid
* `lst` marks the current transmission cycle as the last element of a stream
* `rdy` indicates that the receiver is ready to receive
* `src` and `dst` provide source/destination routing information (optional)
.AXI4-Stream Compatibility
[NOTE]
The interface names and the underlying protocol is compatible to the AXI4-Stream protocol standard.
The interface names (except for `src` and `dst`) and the underlying protocol is compatible to the AXI4-Stream protocol standard.
A processor top entity with a AXI4-Stream-compatible interfaces can be found in `rtl/system_inegration`.
More information regarding this alternate top entity can be found in in the user guide:
https://stnolting.github.io/neorv32/ug/#_packaging_the_processor_as_vivado_ip_block
Expand Down Expand Up @@ -85,6 +88,16 @@ The current status of the RX and TX FIFOs can be determined via the control regi
`SLINK_CTRL_TX_*` flags.


**Stream Routing Information**

Both stream link interface provide an optional port for routing information: `slink_tx_dst_o` (AXI stream's `TDEST`)
can be used to set a destination address when using a switch/interconnect to access several stream sinks. `slink_rx_src_i`
(AXI stream's `TID`) can be used to determine the source when several sources can send data via a switch/interconnect.
The routing information can be set/read via the `ROUTE` interface registers. Note that all routing information is also
fully buffered by the internal RX/TX FIFOs. RX routing information has to be read **after** reading the according RX
data. Vice versa, TX routing information has to be set **before** writing the according TX data.


**Interrupts**

The SLINK module provides two independent interrupt channels: one for RX events and one for TX events.
Expand Down Expand Up @@ -124,7 +137,9 @@ interrupt-causing condition is resolved (e.g. by reading from the RX FIFO).
<| `23:22` _reserved_ ^| r/- <| _reserved_, read as zero
<| `27:24` `SLINK_CTRL_RX_FIFO_MSB : SLINK_CTRL_RX_FIFO_LSB` ^| r/- <| log2(RX FIFO size)
<| `31:28` `SLINK_CTRL_TX_FIFO_MSB : SLINK_CTRL_TX_FIFO_LSB` ^| r/- <| log2(TX FIFO size)
| `0xffffec04` | - | `31:0` | -/- | _reserved_
.3+<| `0xffffec04` .3+<| `NEORV32_SLINK.ROUTE` <| `3:0` | r/w | TX destination routing information (`slink_tx_dst_o`)
<| `7:4` | r/- | RX source routing information (`slink_rx_src_i`)
<| `31:8` | -/- | _reserved_
| `0xffffec08` | `NEORV32_SLINK.DATA` | `31:0` | r/w | Write data to TX FIFO; read data from RX FIFO
| `0xffffec0c` | `NEORV32_SLINK.DATA_LAST` | `31:0` | r/w | Write data to TX FIFO (and also set "last" signal); read data from RX FIFO
|=======================
30 changes: 16 additions & 14 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090901"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090902"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width

Expand Down Expand Up @@ -119,15 +119,15 @@ package neorv32_package is
-- Internal Memory Types ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
type mem32_t is array (natural range <>) of std_ulogic_vector(31 downto 0); -- memory with 32-bit entries
type mem8_t is array (natural range <>) of std_ulogic_vector(07 downto 0); -- memory with 8-bit entries
type mem8_t is array (natural range <>) of std_ulogic_vector(7 downto 0); -- memory with 8-bit entries

-- Internal Bus Interface -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- bus request --
type bus_req_t is record
addr : std_ulogic_vector(31 downto 0); -- access address
data : std_ulogic_vector(31 downto 0); -- write data
ben : std_ulogic_vector(03 downto 0); -- byte enable
ben : std_ulogic_vector(3 downto 0); -- byte enable
stb : std_ulogic; -- request strobe (single-shot)
rw : std_ulogic; -- 0=read, 1=write
src : std_ulogic; -- access source (1=instruction fetch, 0=data access)
Expand Down Expand Up @@ -167,8 +167,8 @@ package neorv32_package is
-- -------------------------------------------------------------------------------------------
-- request --
type dmi_req_t is record
addr : std_ulogic_vector(06 downto 0);
op : std_ulogic_vector(01 downto 0);
addr : std_ulogic_vector(6 downto 0);
op : std_ulogic_vector(1 downto 0);
data : std_ulogic_vector(31 downto 0);
end record;

Expand Down Expand Up @@ -483,27 +483,27 @@ package neorv32_package is
type ctrl_bus_t is record
-- register file --
rf_wb_en : std_ulogic; -- write back enable
rf_rs1 : std_ulogic_vector(04 downto 0); -- source register 1 address
rf_rs2 : std_ulogic_vector(04 downto 0); -- source register 2 address
rf_rd : std_ulogic_vector(04 downto 0); -- destination register address
rf_rs1 : std_ulogic_vector(4 downto 0); -- source register 1 address
rf_rs2 : std_ulogic_vector(4 downto 0); -- source register 2 address
rf_rd : std_ulogic_vector(4 downto 0); -- destination register address
rf_zero_we : std_ulogic; -- allow/force write access to x0
-- alu --
alu_op : std_ulogic_vector(02 downto 0); -- operation select
alu_op : std_ulogic_vector(2 downto 0); -- operation select
alu_sub : std_ulogic; -- addition/subtraction control
alu_opa_mux : std_ulogic; -- operand A select (0=rs1, 1=PC)
alu_opb_mux : std_ulogic; -- operand B select (0=rs2, 1=IMM)
alu_unsigned : std_ulogic; -- is unsigned ALU operation
alu_cp_trig : std_ulogic_vector(05 downto 0); -- co-processor trigger (one-hot)
alu_cp_trig : std_ulogic_vector(5 downto 0); -- co-processor trigger (one-hot)
-- load/store unit --
lsu_req : std_ulogic; -- trigger memory access request
lsu_rw : std_ulogic; -- 0: read access, 1: write access
lsu_mo_we : std_ulogic; -- memory address and data output register write enable
lsu_fence : std_ulogic; -- fence(.i) operation
lsu_priv : std_ulogic; -- effective privilege mode for load/store
-- instruction word --
ir_funct3 : std_ulogic_vector(02 downto 0); -- funct3 bit field
ir_funct3 : std_ulogic_vector(2 downto 0); -- funct3 bit field
ir_funct12 : std_ulogic_vector(11 downto 0); -- funct12 bit field
ir_opcode : std_ulogic_vector(06 downto 0); -- opcode bit field
ir_opcode : std_ulogic_vector(6 downto 0); -- opcode bit field
-- cpu status --
cpu_priv : std_ulogic; -- effective privilege mode
cpu_sleep : std_ulogic; -- set when CPU is in sleep mode
Expand Down Expand Up @@ -818,18 +818,20 @@ package neorv32_package is
xbus_adr_o : out std_ulogic_vector(31 downto 0);
xbus_dat_o : out std_ulogic_vector(31 downto 0);
xbus_we_o : out std_ulogic;
xbus_sel_o : out std_ulogic_vector(03 downto 0);
xbus_sel_o : out std_ulogic_vector(3 downto 0);
xbus_stb_o : out std_ulogic;
xbus_cyc_o : out std_ulogic;
xbus_dat_i : in std_ulogic_vector(31 downto 0) := (others => 'L');
xbus_ack_i : in std_ulogic := 'L';
xbus_err_i : in std_ulogic := 'L';
-- Stream Link Interface (available if IO_SLINK_EN = true) --
slink_rx_dat_i : in std_ulogic_vector(31 downto 0) := (others => 'L');
slink_rx_src_i : in std_ulogic_vector(3 downto 0) := (others => 'L');
slink_rx_val_i : in std_ulogic := 'L';
slink_rx_lst_i : in std_ulogic := 'L';
slink_rx_rdy_o : out std_ulogic;
slink_tx_dat_o : out std_ulogic_vector(31 downto 0);
slink_tx_dst_o : out std_ulogic_vector(3 downto 0);
slink_tx_val_o : out std_ulogic;
slink_tx_lst_o : out std_ulogic;
slink_tx_rdy_i : in std_ulogic := 'L';
Expand All @@ -855,7 +857,7 @@ package neorv32_package is
spi_clk_o : out std_ulogic;
spi_dat_o : out std_ulogic;
spi_dat_i : in std_ulogic := 'L';
spi_csn_o : out std_ulogic_vector(07 downto 0); -- SPI CS
spi_csn_o : out std_ulogic_vector(7 downto 0); -- SPI CS
-- SDI (available if IO_SDI_EN = true) --
sdi_clk_i : in std_ulogic := 'L';
sdi_dat_o : out std_ulogic;
Expand Down
55 changes: 37 additions & 18 deletions rtl/core/neorv32_slink.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ entity neorv32_slink is
tx_irq_o : out std_ulogic; -- TX interrupt
-- RX stream interface --
slink_rx_data_i : in std_ulogic_vector(31 downto 0); -- input data
slink_rx_src_i : in std_ulogic_vector(3 downto 0); -- routing information
slink_rx_valid_i : in std_ulogic; -- valid input
slink_rx_last_i : in std_ulogic; -- end of stream
slink_rx_ready_o : out std_ulogic; -- ready to receive
-- TX stream interface --
slink_tx_data_o : out std_ulogic_vector(31 downto 0); -- output data
slink_tx_dst_o : out std_ulogic_vector(3 downto 0); -- routing destination
slink_tx_valid_o : out std_ulogic; -- valid output
slink_tx_last_o : out std_ulogic; -- end of stream
slink_tx_ready_i : in std_ulogic -- ready to send
Expand Down Expand Up @@ -87,6 +89,9 @@ architecture neorv32_slink_rtl of neorv32_slink is
end record;
signal ctrl : ctrl_t;

-- routing information --
signal route_dst, route_src : std_ulogic_vector(3 downto 0);

-- stream attributes --
signal rx_last : std_ulogic; -- RX end-of-stream indicator

Expand All @@ -95,8 +100,8 @@ architecture neorv32_slink_rtl of neorv32_slink is
we : std_ulogic; -- write enable
re : std_ulogic; -- read enable
clear : std_ulogic; -- sync reset, high-active
wdata : std_ulogic_vector((1+32)-1 downto 0); -- last + data
rdata : std_ulogic_vector((1+32)-1 downto 0); -- last + data
wdata : std_ulogic_vector((1+4+32)-1 downto 0); -- last + routing + data
rdata : std_ulogic_vector((1+4+32)-1 downto 0); -- last + routing + data
avail : std_ulogic; -- data available?
free : std_ulogic; -- free entry available?
half : std_ulogic; -- half full
Expand All @@ -122,6 +127,7 @@ begin
ctrl.irq_tx_empty <= '0';
ctrl.irq_tx_nhalf <= '0';
ctrl.irq_tx_nfull <= '0';
route_dst <= (others => '0');
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
Expand All @@ -148,6 +154,10 @@ begin
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
ctrl.irq_tx_nfull <= bus_req_i.data(ctrl_irq_tx_nfull_c);
end if;
-- routing information --
if (bus_req_i.addr(3 downto 2) = "01") then
route_dst <= bus_req_i.data(3 downto 0);
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
Expand All @@ -172,6 +182,9 @@ begin
--
bus_rsp_o.data(ctrl_rx_fifo_size3_c downto ctrl_rx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_RX_FIFO), 4));
bus_rsp_o.data(ctrl_tx_fifo_size3_c downto ctrl_tx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_TX_FIFO), 4));
when "01" => -- routing information
bus_rsp_o.data(3 downto 0) <= route_dst;
bus_rsp_o.data(7 downto 4) <= route_src;
when others => -- RTX data register
bus_rsp_o.data <= rx_fifo.rdata(31 downto 0);
end case;
Expand All @@ -186,10 +199,10 @@ begin
rx_fifo_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => SLINK_RX_FIFO,
FIFO_WIDTH => 1+32, -- last + data
FIFO_RSYNC => false, -- "async" read - update FIFO status RIGHT after write access (for slink_rx_ready_o)
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
FIFO_WIDTH => 1+4+32, -- last + routing + data
FIFO_RSYNC => false, -- "async" read - update FIFO status RIGHT after write access (for slink_rx_ready_o)
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
)
port map (
-- control --
Expand All @@ -210,21 +223,26 @@ begin
rx_fifo.clear <= (not ctrl.enable) or ctrl.rx_clr;
rx_fifo.re <= '1' when (bus_req_i.stb = '1') and (bus_req_i.rw = '0') and (bus_req_i.addr(3) = '1') else '0';

rx_fifo.we <= slink_rx_valid_i;
rx_fifo.wdata(31 downto 0) <= slink_rx_data_i;
rx_fifo.wdata(32) <= slink_rx_last_i;
slink_rx_ready_o <= rx_fifo.free;
rx_fifo.we <= slink_rx_valid_i;
rx_fifo.wdata(31 downto 0) <= slink_rx_data_i;
rx_fifo.wdata(35 downto 32) <= slink_rx_src_i;
rx_fifo.wdata(36) <= slink_rx_last_i;
slink_rx_ready_o <= rx_fifo.free;

-- backup RX attributes for current access --
rx_attributes: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
rx_last <= '0';
rx_last <= '0';
route_src <= (others => '0');
elsif rising_edge(clk_i) then
if (rx_fifo.clear = '1') then
rx_last <= '0';
elsif (rx_fifo.re = '1') then
rx_last <= rx_fifo.rdata(32);
rx_last <= rx_fifo.rdata(36);
end if;
if (rx_fifo.re = '1') then
route_src <= rx_fifo.rdata(35 downto 32);
end if;
end if;
end process rx_attributes;
Expand All @@ -248,10 +266,10 @@ begin
tx_fifo_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => SLINK_TX_FIFO,
FIFO_WIDTH => 1+32, -- last + data
FIFO_RSYNC => false, -- "async" read - update FIFO status RIGHT after read access (for slink_tx_valid_o)
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
FIFO_WIDTH => 1+4+32, -- last + routing + data
FIFO_RSYNC => false, -- "async" read - update FIFO status RIGHT after read access (for slink_tx_valid_o)
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
)
port map (
-- control --
Expand All @@ -271,11 +289,12 @@ begin

tx_fifo.clear <= (not ctrl.enable) or ctrl.tx_clr;
tx_fifo.we <= '1' when (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(3) = '1') else '0';
tx_fifo.wdata <= bus_req_i.addr(2) & bus_req_i.data; -- last-flag is set implicitly via access address (RTX_LAST register)
tx_fifo.wdata <= bus_req_i.addr(2) & route_dst & bus_req_i.data; -- last-flag is set implicitly via access address (RTX_LAST register)

tx_fifo.re <= slink_tx_ready_i;
slink_tx_data_o <= tx_fifo.rdata(31 downto 0);
slink_tx_last_o <= tx_fifo.rdata(32);
slink_tx_dst_o <= tx_fifo.rdata(35 downto 32);
slink_tx_last_o <= tx_fifo.rdata(36);
slink_tx_valid_o <= tx_fifo.avail;

-- interrupt generator --
Expand Down
Loading

0 comments on commit c5dd617

Please sign in to comment.