Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add SLINK routing information ports #908

Merged
merged 9 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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