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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimize FIFO component to improve mapping #828

Merged
merged 3 commits into from
Feb 23, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Link |
|:----:|:-------:|:--------|:----:|
| 23.02.2024 | 1.9.5.8 | optimize FIFO component to improve technology mapping (inferring blockRAM for "async read" configuration); :bug: fix SLINK status flag delay | [#828](https://github.com/stnolting/neorv32/pull/828) |
| 23.02.2024 | 1.9.5.7 | fix FIFO synthesis issue (Vivado cannot infer block RAM nor LUT-RAM) | [#827](https://github.com/stnolting/neorv32/pull/827) |
| 20.02.2024 | 1.9.5.6 | :bug: fix bug in `mip.firq` CSR access; `mip.firq` bits are now read-write - software can trigger FIRQs by writing `1` to the according CSR bit | [#821](https://github.com/stnolting/neorv32/pull/821) |
| 19.02.2024 | 1.9.5.5 | SLINK: add native hardware support for AXI-stream's "tlast" signal | [#815](https://github.com/stnolting/neorv32/pull/815) |
Expand Down
170 changes: 121 additions & 49 deletions rtl/core/neorv32_fifo.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ architecture neorv32_fifo_rtl of neorv32_fifo is
-- FIFO control --
signal we, re : std_ulogic; -- write-/read-enable
signal w_pnt, r_pnt : std_ulogic_vector(index_size_f(fifo_depth_c) downto 0); -- write/read pointer
signal w_nxt, r_nxt : std_ulogic_vector(index_size_f(fifo_depth_c) downto 0);

-- read access pointer register for async. read --
signal r_pnt_ff : std_ulogic_vector(index_size_f(fifo_depth_c) downto 0);

-- status --
signal match, empty, full, half, free, avail : std_ulogic;
Expand All @@ -99,21 +103,19 @@ begin
w_pnt <= (others => '0');
r_pnt <= (others => '0');
elsif rising_edge(clk_i) then
-- write port --
if (clear_i = '1') then
w_pnt <= (others => '0');
elsif (we = '1') then
w_pnt <= std_ulogic_vector(unsigned(w_pnt) + 1);
end if;
-- read port --
if (clear_i = '1') then
r_pnt <= (others => '0');
elsif (re = '1') then
r_pnt <= std_ulogic_vector(unsigned(r_pnt) + 1);
end if;
w_pnt <= w_nxt;
r_pnt <= r_nxt;
end if;
end process pointer_update;

-- async pointer update --
w_nxt <= (others => '0') when (clear_i = '1') else std_ulogic_vector(unsigned(w_pnt) + 1) when (we = '1') else w_pnt;
r_nxt <= (others => '0') when (clear_i = '1') else std_ulogic_vector(unsigned(r_pnt) + 1) when (re = '1') else r_pnt;


-- Status ---------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------

-- more than 1 FIFO entries --
check_large:
if (fifo_depth_c > 1) generate
Expand All @@ -137,68 +139,137 @@ begin
avail <= not empty;


-- Write Access ---------------------------------------------------------------------------
-- Write Access (with Reset) --------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
memory_full_reset: -- cannot be mapped to block RAM!
memory_full_reset: -- cannot be mapped to memory primitives
if FULL_RESET generate
fifo_write_rst: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
fifo_mem <= (others => (others => '0'));
fifo_reg <= (others => '0');
elsif rising_edge(clk_i) then
if (we = '1') then
if (fifo_depth_c > 1) then
fifo_mem(to_integer(unsigned(w_pnt(w_pnt'left-1 downto 0)))) <= wdata_i;
else

-- just 1 FIFO entry --
fifo_write_reset_small:
if (fifo_depth_c = 1) generate
write_reset_small: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
fifo_reg <= (others => '0');
elsif rising_edge(clk_i) then
if (we = '1') then
fifo_reg <= wdata_i;
end if;
end if;
end if;
end process fifo_write_rst;
end process write_reset_small;
end generate;

-- more than 1 FIFO entries --
fifo_write_reset_large:
if (fifo_depth_c > 1) generate
write_reset_large: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
fifo_mem <= (others => (others => '0'));
elsif rising_edge(clk_i) then
if (we = '1') then
fifo_mem(to_integer(unsigned(w_pnt(w_pnt'left-1 downto 0)))) <= wdata_i;
end if;
end if;
end process write_reset_large;
end generate;

end generate;

memory_no_reset: -- no reset to infer block RAM

-- Write Access (without Reset) -----------------------------------------------------------
-- -------------------------------------------------------------------------------------------
memory_no_reset: -- no reset to infer memory primitives
if not FULL_RESET generate
fifo_write: process(clk_i)
begin
if rising_edge(clk_i) then
if (we = '1') then
if (fifo_depth_c > 1) then
fifo_mem(to_integer(unsigned(w_pnt(w_pnt'left-1 downto 0)))) <= wdata_i;
else

-- just 1 FIFO entry --
fifo_write_noreset_small:
if (fifo_depth_c = 1) generate
write_small: process(clk_i)
begin
if rising_edge(clk_i) then
if (we = '1') then
fifo_reg <= wdata_i;
end if;
end if;
end if;
end process fifo_write;
end process write_small;
end generate;

-- more than 1 FIFO entries --
fifo_write_noreset_large:
if (fifo_depth_c > 1) generate
write_large: process(clk_i)
begin
if rising_edge(clk_i) then
if (we = '1') then
fifo_mem(to_integer(unsigned(w_pnt(w_pnt'left-1 downto 0)))) <= wdata_i;
end if;
end if;
end process write_large;
end generate;

end generate;


-- Read Access ----------------------------------------------------------------------------
-- Asynchronous Read Access ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
fifo_read_async: -- asynchronous read
fifo_read_async:
if not FIFO_RSYNC generate
rdata_o <= fifo_mem(to_integer(unsigned(r_pnt(r_pnt'left-1 downto 0)))) when (fifo_depth_c > 1) else fifo_reg;

-- just 1 FIFO entry --
fifo_read_async_small:
if (fifo_depth_c = 1) generate
rdata_o <= fifo_reg;
end generate;

-- more than 1 FIFO entries --
fifo_read_async_large:
if (fifo_depth_c > 1) generate
async_r_pnt_reg: process(clk_i)
begin
if rising_edge(clk_i) then
r_pnt_ff <= r_nxt; -- individual read address register; allows mapping "async" FIFOs to memory primitives
end if;
end process async_r_pnt_reg;
rdata_o <= fifo_mem(to_integer(unsigned(r_pnt_ff(r_pnt_ff'left-1 downto 0))));
end generate;

-- status --
free_o <= free;
avail_o <= avail;
half_o <= half;

end generate;

fifo_read_sync: -- synchronous read

-- Synchronous Read Access ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
fifo_read_sync:
if FIFO_RSYNC generate
sync_read: process(clk_i)
begin
if rising_edge(clk_i) then
if (fifo_depth_c > 1) then
rdata_o <= fifo_mem(to_integer(unsigned(r_pnt(r_pnt'left-1 downto 0))));
else

-- just 1 FIFO entry --
fifo_read_sync_small:
if (fifo_depth_c = 1) generate
sync_read_small: process(clk_i)
begin
if rising_edge(clk_i) then
rdata_o <= fifo_reg;
end if;
end if;
end process sync_read;
-- status --
end process sync_read_small;
end generate;

-- more than 1 FIFO entries --
fifo_read_sync_large:
if (fifo_depth_c > 1) generate
sync_read_large: process(clk_i)
begin
if rising_edge(clk_i) then
rdata_o <= fifo_mem(to_integer(unsigned(r_pnt(r_pnt'left-1 downto 0))));
end if;
end process sync_read_large;
end generate;

-- registered status --
sync_status: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
Expand All @@ -211,6 +282,7 @@ begin
half_o <= half;
end if;
end process sync_status;

end generate;


Expand Down
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ package neorv32_package is

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

Expand Down
16 changes: 8 additions & 8 deletions rtl/core/neorv32_slink.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,10 @@ begin
rx_fifo_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => SLINK_RX_FIFO,
FIFO_WIDTH => 32+1, -- data + last-flag
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
FIFO_WIDTH => 32+1, -- data + last-flag
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 Down Expand Up @@ -264,10 +264,10 @@ begin
tx_fifo_inst: entity neorv32.neorv32_fifo
generic map (
FIFO_DEPTH => SLINK_TX_FIFO,
FIFO_WIDTH => 32+1, -- data + last-flag
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FULL_RESET => false -- no HW reset, try to infer BRAM
FIFO_WIDTH => 32+1, -- data + last-flag
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 Down