From: Tobias Weber Date: Wed, 12 Sep 2018 14:00:53 +0000 (+0200) Subject: new version of circular buffer. needs testing in simulation and hardware. X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=8e1924947427f9bb812231a7ef44ac79365bce8d;p=trb3.git new version of circular buffer. needs testing in simulation and hardware. --- diff --git a/mupix/Mupix8/sources/Datapath/CircularMemory.vhd b/mupix/Mupix8/sources/Datapath/CircularMemory.vhd index 143b2c6..21fe871 100644 --- a/mupix/Mupix8/sources/Datapath/CircularMemory.vhd +++ b/mupix/Mupix8/sources/Datapath/CircularMemory.vhd @@ -1,7 +1,8 @@ ------------------------------------------------------------------------------- ---Circular Memory to save sensor data +-- Circular Memory to buffer sensor data +-- Maximum address width is limited by used amount of block memory -- Note that writing into a full buffer will overwrite parts of the old data ---T. Weber, University Mainz +-- T. Weber, University Mainz ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; @@ -18,7 +19,7 @@ entity CircularMemory is ); port( clk : in std_logic; -- clock input - rst : in std_logic; -- reset + rst : in std_logic; -- reset wr_en : in std_logic; -- write enable data_in : in std_logic_vector(g_datawidth - 1 downto 0); -- input word rd_en : in std_logic; --read enable @@ -28,8 +29,7 @@ entity CircularMemory is empty : out std_logic; --empty flag full : out std_logic; --full flag almost_empty : out std_logic; --one more word remaining in buffer - almost_full : out std_logic; --one more word to write before buffer overflow - fillcnt : out std_logic_vector(g_addresswidth downto 0); -- number of words in circular buffer + fillcnt : out std_logic_vector(g_addresswidth - 1 downto 0); -- number of words in circular buffer inword_freq : out std_logic_vector(31 downto 0); -- number of input words per second outword_freq : out std_logic_vector(31 downto 0) -- number of output words per second ); @@ -39,8 +39,8 @@ architecture RTL of CircularMemory is component RAM_DP_8192_32 is port ( - WrAddress : in std_logic_vector(11 downto 0); - RdAddress : in std_logic_vector(11 downto 0); + WrAddress : in std_logic_vector(12 downto 0); + RdAddress : in std_logic_vector(12 downto 0); Data : in std_logic_vector(31 downto 0); WE : in std_logic; RdClock : in std_logic; @@ -56,128 +56,142 @@ architecture RTL of CircularMemory is signal inword_counter, outword_counter : unsigned(31 downto 0) := (others => '0'); --read and write pointers - constant c_high_address : integer := 2**g_addresswidth; - signal readpointer : integer range 0 to c_high_address - 1 := 0; - signal writepointer : integer range 0 to c_high_address - 1 := 0; - signal words_in_buffer : integer range 0 to c_high_address := 0; - signal read_write_pointer_offset : integer range -(c_high_address - 1) to c_high_address - 1 := 0; + constant c_ram_addresswidth : integer := 13; + constant c_capacity : integer := 2**g_addresswidth; + constant c_capacity2 : integer := 2**g_addresswidth - 2; + constant zeros : std_logic_vector(c_ram_addresswidth - 1 downto 0) := (others => '0'); + signal readpointer : unsigned(g_addresswidth - 1 downto 0) := (others => '0'); + signal writepointer : unsigned(g_addresswidth - 1 downto 0) := (others => '0'); + signal fill_cnt_i : unsigned(g_addresswidth - 1 downto 0) := (others => '0'); + signal read_write_pointer_offset : integer range -(c_capacity - 1) to c_capacity - 1 := 0; --wires to block memory signal WrEn_mem : std_logic; - signal WrAddr_mem : std_logic_vector(g_addresswidth - 1 downto 0); - signal Din_mem : std_logic_vector(g_datawidth - 1 downto 0); - signal ReAddr_mem : std_logic_vector(g_addresswidth - 1 downto 0); - signal Dout_mem : std_logic_vector(g_datawidth - 1 downto 0); - - signal empty_i : std_logic; - signal full_i : std_logic; - signal rd_en_i : std_logic; - signal wr_en_i : std_logic; + signal WrAddr_mem : std_logic_vector(12 downto 0); + signal Din_mem : std_logic_vector(31 downto 0); + signal ReAddr_mem : std_logic_vector(12 downto 0); + signal Dout_mem : std_logic_vector(31 downto 0); + signal fallthrough_en : std_logic; + signal Dout_fall : std_logic_vector(31 downto 0); + + signal empty_i : std_logic := '0'; + signal almost_empty_i : std_logic := '0'; + signal full_i : std_logic := '0'; + signal rd_en_i : std_logic := '0'; + signal wr_en_i : std_logic := '0'; signal increment_wd_cnt : std_logic := '0'; - signal decrement_wd_cnt : std_logic := '0'; + signal decrement_wd_cnt : std_logic_vector(1 downto 0) := "00"; + signal read_last : std_logic := '0'; begin - RAM_DP_4096_32_1: entity work.RAM_DP_8192_32 - port map ( - WrAddress => WrAddr_mem, - RdAddress => ReAddr_mem, - Data => Din_mem, - WE => WrEn_mem, - RdClock => clk, - RdClockEn => '1', - Reset => rst, - WrClock => clk, - WrClockEn => '1', - Q => Dout_mem); - - write_proc : process(clk) is - begin - if rising_edge(clk) then - if rst = '1' then - writepointer <= 0; - increment_wd_cnt <= '0'; - else - if wr_en_i = '1' then - increment_wd_cnt <= '1'; - if writepointer = c_high_address - 1 then - writepointer <= 0; - else - writepointer <= writepointer + 1; - end if; - else - writepointer <= writepointer; - increment_wd_cnt <= '0'; - end if; - end if; - end if; - end process write_proc; + assert g_addresswidth < 14 report "address width of circular buffer has to be smaller than 14" severity failure; + assert g_datawidth = 32 report "data width of trb is 32 bit" severity failure; - WrAddr_mem <= std_logic_vector(to_unsigned(writepointer, g_addresswidth)); + rd_en_i <= not empty_i and rd_en; + wr_en_i <= (wr_en and not full_i) when g_boundedbuf = true else wr_en; + +RAM_DP_4096_32_1: entity work.RAM_DP_8192_32 + port map ( + WrAddress => WrAddr_mem, + RdAddress => ReAddr_mem, + Data => Din_mem, + WE => WrEn_mem, + RdClock => clk, + RdClockEn => '1', + Reset => rst, + WrClock => clk, + WrClockEn => '1', + Q => Dout_mem); + + n_gen: if g_addresswidth = c_ram_addresswidth generate + WrAddr_mem <= std_logic_vector(writepointer); + ReAddr_mem <= std_logic_vector(readpointer); + end generate n_gen; + sim_gen: if g_addresswidth < c_ram_addresswidth generate + -- below is when simulating with smaller ram addresses + WrAddr_mem <= zeros(c_ram_addresswidth - 1 downto writepointer'length) & std_logic_vector(writepointer); + ReAddr_mem <= zeros(c_ram_addresswidth - 1 downto readpointer'length) & std_logic_vector(readpointer); + end generate sim_gen; Din_mem <= data_in; WrEn_mem <= wr_en_i; + -- precompute read_write_offset_proc : process(offset, writepointer) is begin - read_write_pointer_offset <= writepointer - to_integer(unsigned(offset)) after 2 ns; + read_write_pointer_offset <= to_integer(writepointer) - to_integer(unsigned(offset)) after 2 ns; end process read_write_offset_proc; - read_proc : process(clk) is + -- update pointers to memory locations + pointer_proc : process(clk) begin if rising_edge(clk) then if rst = '1' then - readpointer <= 0; - decrement_wd_cnt <= '0'; + writepointer <= (others => '0'); + readpointer <= (others => '0'); else - if offset_en = '1' then - if read_write_pointer_offset >= 0 then - readpointer <= read_write_pointer_offset; - else - readpointer <= c_high_address + read_write_pointer_offset; + if full_i = '0' then + readpointer <= readpointer; + writepointer <= writepointer; + if wr_en_i = '1' then -- update write pointer + writepointer <= writepointer + 1; end if; - elsif rd_en_i = '1' then - decrement_wd_cnt <= '1'; - if readpointer = c_high_address - 1 then - readpointer <= 0; - else + if rd_en_i = '1' then -- update read pointer readpointer <= readpointer + 1; end if; else - decrement_wd_cnt <= '0'; - readpointer <= readpointer; + if wr_en_i = '1' then -- update read and write counter + writepointer <= writepointer + 1; + readpointer <= readpointer + 1; + elsif rd_en_i = '1' then -- update read counter + readpointer <= readpointer + 1; + else -- do nothing + readpointer <= readpointer; + writepointer <= writepointer; + end if; + end if; -- end full + -- react on offset enable + if offset_en = '1' then + if read_write_pointer_offset >= 0 then + readpointer <= to_unsigned(read_write_pointer_offset, g_addresswidth); + else + readpointer <= to_unsigned(c_capacity + read_write_pointer_offset, g_addresswidth); + end if; end if; - end if; - end if; - end process read_proc; + end if; -- end rst + end if; -- end clk + end process; - ReAddr_mem <= std_logic_vector(to_unsigned(readpointer, g_addresswidth)); - - word_counter_proc : process(clk) is + -- word fall through for equal write and read pointer + fallthrough_proc : process(clk) begin if rising_edge(clk) then if rst = '1' then - words_in_buffer <= 0; - elsif offset_en = '1' then - words_in_buffer <= to_integer(unsigned(offset)); + Dout_fall <= (others => '0'); + fallthrough_en <= '0'; else - words_in_buffer <= words_in_buffer; - if increment_wd_cnt = '1' and decrement_wd_cnt = '0' then - if words_in_buffer < c_high_address then - words_in_buffer <= words_in_buffer + 1; - else - words_in_buffer <= words_in_buffer; - end if; - elsif increment_wd_cnt = '0' and decrement_wd_cnt = '1' then - if words_in_buffer > 0 then - words_in_buffer <= words_in_buffer - 1; - else - words_in_buffer <= 0; - end if; + fallthrough_en <= '0'; + if wr_en_i = '1' and readpointer = writepointer then + Dout_fall <= data_in; + fallthrough_en <= '1'; end if; end if; end if; - end process word_counter_proc; + end process; + -- compute number of data elements in buffer + fill_cnt_proc : process(readpointer, writepointer) + begin + if writepointer > readpointer then + fill_cnt_i <= writepointer - readpointer; + elsif writepointer < readpointer then + fill_cnt_i <= c_capacity - (readpointer - writepointer); + else + fill_cnt_i <= (others => '0'); + end if; + end process fill_cnt_proc; + + -- count read/write frequency throughput_proc : process (clk) is begin if rising_edge(clk) then @@ -205,16 +219,14 @@ begin end if; end process throughput_proc; - empty_i <= '1' when words_in_buffer = 0 else '0'; - full_i <= '1' when words_in_buffer = c_high_address else '0'; - rd_en_i <= not empty_i and rd_en; - wr_en_i <= (wr_en and not full_i) when g_boundedbuf = true else wr_en; + empty_i <= '1' when readpointer = writepointer else '0'; + full_i <= '1' when to_integer(fill_cnt_i) = c_capacity2 else '0'; + -- outputs empty <= empty_i; - almost_empty <= '1' when (words_in_buffer < 3) else '0'; full <= full_i; - almost_full <= '1' when words_in_buffer >= c_high_address - 1 else '0'; - fillcnt <= std_logic_vector(to_unsigned(words_in_buffer, g_addresswidth + 1)); - data_out <= Dout_mem; + almost_empty <= '1' when fill_cnt_i < 2 else '0'; + fillcnt <= std_logic_vector(fill_cnt_i); + data_out <= Dout_mem when fallthrough_en = '0' else Dout_fall; end architecture RTL; diff --git a/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd b/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd index 79940c6..e0a7eda 100644 --- a/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd +++ b/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd @@ -2,7 +2,7 @@ -- Entities for Mupix Readout with slow control access to TRB slow control -- Tobias Weber -- Ruhr Unversitaet Bochum ------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; @@ -61,8 +61,7 @@ architecture rtl of MupixTRBReadout is empty : out std_logic; full : out std_logic; almost_empty : out std_logic; - almost_full : out std_logic; - fillcnt : out std_logic_vector(g_addresswidth downto 0); + fillcnt : out std_logic_vector(g_addresswidth - 1 downto 0); inword_freq : out std_logic_vector(31 downto 0); outword_freq : out std_logic_vector(31 downto 0) ); @@ -138,7 +137,7 @@ architecture rtl of MupixTRBReadout is data_out : out std_logic_vector(g_datawidth - 1 downto 0) ); end component ReadoutController; - + signal reset_reg : std_logic := '0'; signal readout_mode_i : std_logic_vector(1 downto 0) := "00"; @@ -150,7 +149,7 @@ architecture rtl of MupixTRBReadout is signal wordin_freq : std_logic_vector(32*g_mupix_links - 1 downto 0) := (others => '0'); signal fifo_full_o : std_logic; - signal cycl_fillcnt : std_logic_vector(g_cyc_mem_address_width downto 0); + signal cycl_fillcnt : std_logic_vector(g_cyc_mem_address_width - 1 downto 0); signal cycl_inword_freq : std_logic_vector(31 downto 0); signal cycl_outword_freq : std_logic_vector(31 downto 0); signal cycl_empty : std_logic; @@ -261,7 +260,6 @@ begin empty => cycl_empty, full => cycl_full, almost_empty => cycl_almost_empty, - almost_full => open, fillcnt => cycl_fillcnt, inword_freq => cycl_inword_freq, outword_freq => cycl_outword_freq @@ -425,10 +423,10 @@ begin SLV_DATA_OUT(0) <= fifo_full_o; SLV_ACK_OUT <= '1'; when x"0108" => - SLV_DATA_OUT(g_cyc_mem_address_width downto 0) <= cycl_fillcnt; - SLV_DATA_OUT(31) <= cycl_empty; - SLV_DATA_OUT(30) <= cycl_full; - SLV_ACK_OUT <= '1'; + SLV_DATA_OUT(g_cyc_mem_address_width -1 downto 0) <= cycl_fillcnt; + SLV_DATA_OUT(31) <= cycl_empty; + SLV_DATA_OUT(30) <= cycl_full; + SLV_ACK_OUT <= '1'; when x"0109" => SLV_DATA_OUT <= cycl_inword_freq; SLV_ACK_OUT <= '1'; diff --git a/mupix/Mupix8/sources/Datapath/ReadoutController.vhd b/mupix/Mupix8/sources/Datapath/ReadoutController.vhd index 3206e58..6c3cc35 100644 --- a/mupix/Mupix8/sources/Datapath/ReadoutController.vhd +++ b/mupix/Mupix8/sources/Datapath/ReadoutController.vhd @@ -2,13 +2,13 @@ -- Readout Controller for Circular Memory -- Tobias Weber -- Ruhr Unversitaet Bochum ------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; ----------------------------------------------------------------------------- --- mode = 0: read single word from buffer, return 0x0 if empty +-- mode = 0: read single word from buffer, return 0x0 if empty -- the frame header and trailer are missing in this mode -- mode = 1: read until buffer empty or maximum of words to read -- mode = 2: wait for words after trigger, set read offset and start reading @@ -22,7 +22,7 @@ entity ReadoutController is ); port( clk : in std_logic; -- clock input - rst : in std_logic; -- reset input + rst : in std_logic; -- reset input start : in std_logic; -- start reading mode : in std_logic_vector(1 downto 0); -- readout mode writes_after_trig : in std_logic_vector(g_addresswidth - 1 downto 0); -- clock cycles after trigger before starting readout (needs to be at least two) @@ -43,7 +43,7 @@ architecture RTL of ReadoutController is constant c_frame_start : std_logic_vector(g_datawidth - 1 downto 0) := x"FABEABBA"; constant c_frame_end : std_logic_vector(g_datawidth - 1 downto 0) := x"BEEFBEEF"; - --readout state type, in mode 1, 2 a header and trailer will be put + --readout state type, in mode 1, 2 a header and trailer will be put --at beginning and end of readout frame type t_readout_state_type is (idle, header, read_single, read, wait_memory, wait_trigger, trailer); signal readout_fsm : t_readout_state_type := idle; @@ -116,12 +116,13 @@ begin when header => busy <= '1'; data_valid <= '1'; - headercounter <= headercounter + 1; case headercounter is when 0 => - data_out <= c_frame_start; + data_out <= c_frame_start; + headercounter <= 1; when 1 => - data_out <= sensor_id; + data_out <= sensor_id; + headercounter <= 2; when 2 => data_out <= std_logic_vector(framecounter); framecounter <= framecounter + 1; @@ -195,8 +196,8 @@ begin busy <= '1'; data_valid <= '1'; readout_fsm <= trailer; - trailercounter <= trailercounter + 1; if trailercounter = 0 then + trailercounter <= 1; data_out(g_addresswidth - 1 downto 0) <= std_logic_vector(wordcounter); else data_out <= c_frame_end;