diff --git a/modules/wishbone/wb_dma/Manifest.py b/modules/wishbone/wb_dma/Manifest.py index 9f267a12524b759e23426b4bc8af2e18456ddccc..e549ae1c6faabf20b3bd841b6e1227a2eac32897 100644 --- a/modules/wishbone/wb_dma/Manifest.py +++ b/modules/wishbone/wb_dma/Manifest.py @@ -1 +1 @@ -files = [ "xwb_dma.vhd" ]; +files = [ "xwb_dma.vhd", "xwb_streamer.vhd" ]; diff --git a/modules/wishbone/wb_dma/xwb_streamer.vhd b/modules/wishbone/wb_dma/xwb_streamer.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f119b3c3e931d81996e12bafb3a1e4db2bb0444c --- /dev/null +++ b/modules/wishbone/wb_dma/xwb_streamer.vhd @@ -0,0 +1,159 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wishbone_pkg.all; + +entity xwb_streamer is + generic( + -- Value 0 cannot stream + -- Value 1 only slaves with async ACK can stream + -- Value 2 only slaves with combined latency = 2 can stream + -- Value 3 only slaves with combined latency = 6 can stream + -- Value 4 only slaves with combined latency = 14 can stream + -- .... + logRingLen : integer := 4 + ); + port( + -- Common wishbone signals + clk_i : in std_logic; + rst_n_i : in std_logic; + -- Master reader port + r_master_i : in t_wishbone_master_in; + r_master_o : out t_wishbone_master_out; + -- Master writer port + w_master_i : in t_wishbone_master_in; + w_master_o : out t_wishbone_master_out); +end xwb_streamer; + +architecture rtl of xwb_streamer is + constant ringLen : integer := 2**logRingLen; + type ring_t is array (ringLen-1 downto 0) of t_wishbone_data; + + -- Ring buffer for shipping data from read master to write master + signal ring : ring_t; + + -- State registers (pointer into the ring) + -- Invariant: read_issue_offset >= read_result_offset >= write_issue_offset >= write_result_offset + -- read_issue_offset - write_result_offset <= ringLen (*NOT* strict '<') + signal read_issue_offset : unsigned(logRingLen downto 0); + signal read_result_offset : unsigned(logRingLen downto 0); + signal write_issue_offset : unsigned(logRingLen downto 0); + signal write_result_offset : unsigned(logRingLen downto 0); + + -- Registered wishbone control signals + signal r_master_o_CYC : std_logic; + signal w_master_o_CYC : std_logic; + signal r_master_o_STB : std_logic; + signal w_master_o_STB : std_logic; + + function active_high(x : boolean) + return std_logic is + begin + if (x) then + return '1'; + else + return '0'; + end if; + end active_high; + + function index(x : unsigned(logRingLen downto 0)) + return integer is + begin + if logRingLen > 0 then + return to_integer(x(logRingLen-1 downto 0)); + else + return 0; + end if; + end index; + +begin + -- Hard-wired master pins + r_master_o.CYC <= r_master_o_CYC; + w_master_o.CYC <= w_master_o_CYC; + r_master_o.STB <= r_master_o_STB; + w_master_o.STB <= w_master_o_STB; + r_master_o.ADR <= (others => '0'); + w_master_o.ADR <= (others => '0'); + r_master_o.SEL <= (others => '1'); + w_master_o.SEL <= (others => '1'); + r_master_o.WE <= '0'; + w_master_o.WE <= '1'; + r_master_o.DAT <= (others => '0'); + w_master_o.DAT <= ring(index(write_issue_offset)); + + main : process(clk_i) + variable read_issue_progress : boolean; + variable read_result_progress : boolean; + variable write_issue_progress : boolean; + variable write_result_progress : boolean; + + variable new_read_issue_offset : unsigned(logRingLen downto 0); + variable new_read_result_offset : unsigned(logRingLen downto 0); + variable new_write_issue_offset : unsigned(logRingLen downto 0); + variable new_write_result_offset : unsigned(logRingLen downto 0); + + variable ring_boundary : boolean; + variable ring_high : boolean; + variable ring_full : boolean; + begin + if (rising_edge(clk_i)) then + if (rst_n_i = '0') then + read_issue_offset <= (others => '0'); + read_result_offset <= (others => '0'); + write_issue_offset <= (others => '0'); + write_result_offset <= (others => '0'); + + r_master_o_CYC <= '0'; + w_master_o_CYC <= '0'; + r_master_o_STB <= '0'; + w_master_o_STB <= '0'; + else + -- Detect bus progress + read_issue_progress := r_master_o_STB = '1' and r_master_i.STALL = '0'; + write_issue_progress := w_master_o_STB = '1' and w_master_i.STALL = '0'; + read_result_progress := r_master_o_CYC = '1' and (r_master_i.ACK = '1' or r_master_i.ERR = '1' or r_master_i.RTY = '1'); + write_result_progress := w_master_o_CYC = '1' and (w_master_i.ACK = '1' or w_master_i.ERR = '1' or w_master_i.RTY = '1'); + + -- Advance read pointers + if read_issue_progress then + new_read_issue_offset := read_issue_offset + 1; + else + new_read_issue_offset := read_issue_offset; + end if; + if read_result_progress then + ring(index(read_result_offset)) <= r_master_i.DAT; + new_read_result_offset := read_result_offset + 1; + else + new_read_result_offset := read_result_offset; + end if; + + -- Advance write pointers + if write_issue_progress then + new_write_issue_offset := write_issue_offset + 1; + else + new_write_issue_offset := write_issue_offset; + end if; + if write_result_progress then + new_write_result_offset := write_result_offset + 1; + else + new_write_result_offset := write_result_offset; + end if; + + ring_boundary := index(new_read_issue_offset) = index(new_write_result_offset); + ring_high := new_read_issue_offset(logRingLen) /= new_write_result_offset(logRingLen); + ring_full := ring_boundary and ring_high; + + r_master_o_STB <= active_high (not ring_full); + r_master_o_CYC <= active_high((not ring_full) or + (new_read_result_offset /= new_read_issue_offset)); + w_master_o_STB <= active_high (new_write_issue_offset /= new_read_result_offset); + w_master_o_CYC <= active_high (new_write_result_offset /= new_read_result_offset); + + read_issue_offset <= new_read_issue_offset; + read_result_offset <= new_read_result_offset; + write_issue_offset <= new_write_issue_offset; + write_result_offset <= new_write_result_offset; + end if; + end if; + end process; +end rtl; diff --git a/modules/wishbone/wishbone_pkg.vhd b/modules/wishbone/wishbone_pkg.vhd index 4b88b923d07a08eefa87e78d94a74cca5128bb45..35fd0b42c27995999f9ee3bed782ca6a30ff55d8 100644 --- a/modules/wishbone/wishbone_pkg.vhd +++ b/modules/wishbone/wishbone_pkg.vhd @@ -368,6 +368,29 @@ package wishbone_pkg is slave2_i : in t_wishbone_slave_in; slave2_o : out t_wishbone_slave_out); end component; + + -- Just like the DMA controller, but constantly at address 0 + component xwb_streamer is + generic( + -- Value 0 cannot stream + -- Value 1 only slaves with async ACK can stream + -- Value 2 only slaves with combined latency = 2 can stream + -- Value 3 only slaves with combined latency = 6 can stream + -- Value 4 only slaves with combined latency = 14 can stream + -- .... + logRingLen : integer := 4 + ); + port( + -- Common wishbone signals + clk_i : in std_logic; + rst_n_i : in std_logic; + -- Master reader port + r_master_i : in t_wishbone_master_in; + r_master_o : out t_wishbone_master_out; + -- Master writer port + w_master_i : in t_wishbone_master_in; + w_master_o : out t_wishbone_master_out); + end component; component wb_gpio_port generic (