From 2d96d8065d16e8b2e0af0a010cb4260019daf92f Mon Sep 17 00:00:00 2001 From: Tobias Weber Date: Thu, 19 Jul 2018 15:28:27 +0200 Subject: [PATCH] replace block memory in circular buffer with ip from Lattice. --- .../sources/Datapath/CircularMemory.vhd | 410 +++++++++--------- .../sources/Datapath/MupixTRBReadout.vhd | 6 +- mupix/Mupix8/tb/MupixTRBReadoutTest.vhd | 2 +- mupix/Mupix8/trb3_periph.prj | 1 + 4 files changed, 209 insertions(+), 210 deletions(-) diff --git a/mupix/Mupix8/sources/Datapath/CircularMemory.vhd b/mupix/Mupix8/sources/Datapath/CircularMemory.vhd index b929e24..ea0d02d 100644 --- a/mupix/Mupix8/sources/Datapath/CircularMemory.vhd +++ b/mupix/Mupix8/sources/Datapath/CircularMemory.vhd @@ -10,215 +10,211 @@ use ieee.numeric_std.all; use work.StdTypes.all; entity CircularMemory is - generic( - g_datawidth : integer := 32; -- width of data words - g_addresswidth : integer := 10; -- width of address pointers, number of words is 2**g_addresswidth - g_clockspeed : integer := 1e8; -- FPGA clock speed in Hz - g_boundedbuf : boolean := false -- stop writing when buffer is full (FIFO mode) - ); - port( - clk : in std_logic; -- clock input - 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 - offset_en : in std_logic; -- set offset between write and read pointer - offset : in std_logic_vector(g_addresswidth - 1 downto 0); -- read - write pointer offset - data_out : out std_logic_vector(g_datawidth - 1 downto 0); -- output word - 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 - 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 - ); + generic( + g_datawidth : integer := 32; -- width of data words + g_addresswidth : integer := 10; -- width of address pointers, number of words is 2**g_addresswidth + g_clockspeed : integer := 1e8; -- FPGA clock speed in Hz + g_boundedbuf : boolean := false -- stop writing when buffer is full (FIFO mode) + ); + port( + clk : in std_logic; -- clock input + 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 + offset_en : in std_logic; -- set offset between write and read pointer + offset : in std_logic_vector(g_addresswidth - 1 downto 0); -- read - write pointer offset + data_out : out std_logic_vector(g_datawidth - 1 downto 0); -- output word + 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 + 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 + ); end entity CircularMemory; architecture RTL of CircularMemory is - - component BlockMemory - generic( - DataWidth : integer := 10; - AddressWidth : integer := 10 - ); - port( - clk : in std_logic; - reset : in std_logic; - WrEn : in std_logic; - WrAddr : in std_logic_vector(AddressWidth - 1 downto 0); - Din : in std_logic_vector(DataWidth - 1 downto 0); - ReAddr : in std_logic_vector(AddressWidth - 1 downto 0); - Dout : out std_logic_vector(DataWidth - 1 downto 0) - ); - end component BlockMemory; - - --counters for write/read frequency - signal ticks_counter : unsigned(f_log2(g_clockspeed) - 1 downto 0) := (others => '0'); - 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; - - --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 increment_wd_cnt : std_logic := '0'; - signal decrement_wd_cnt : std_logic := '0'; - + + component RAM_DP_4096_32 is + port ( + WrAddress : in std_logic_vector(11 downto 0); + RdAddress : in std_logic_vector(11 downto 0); + Data : in std_logic_vector(31 downto 0); + WE : in std_logic; + RdClock : in std_logic; + RdClockEn : in std_logic; + Reset : in std_logic; + WrClock : in std_logic; + WrClockEn : in std_logic; + Q : out std_logic_vector(31 downto 0)); + end component RAM_DP_4096_32; + + --counters for write/read frequency + signal ticks_counter : unsigned(f_log2(g_clockspeed) - 1 downto 0) := (others => '0'); + 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; + + --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 increment_wd_cnt : std_logic := '0'; + signal decrement_wd_cnt : std_logic := '0'; + begin - - memory : entity work.BlockMemory - generic map( - DataWidth => g_datawidth, - AddressWidth => g_addresswidth - ) - port map( - clk => clk, - reset => rst, - WrEn => WrEn_mem, - WrAddr => WrAddr_mem, - Din => Din_mem, - ReAddr => ReAddr_mem, - Dout => 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; - - WrAddr_mem <= std_logic_vector(to_unsigned(writepointer, g_addresswidth)); - Din_mem <= data_in; - WrEn_mem <= wr_en_i; - - read_write_offset_proc : process(offset, writepointer) is - begin - read_write_pointer_offset <= writepointer - to_integer(unsigned(offset)) after 2 ns; - end process read_write_offset_proc; - - read_proc : process(clk) is - begin - if rising_edge(clk) then - if rst = '1' then - readpointer <= 0; - decrement_wd_cnt <= '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; - end if; - elsif rd_en_i = '1' then - decrement_wd_cnt <= '1'; - if readpointer = c_high_address - 1 then - readpointer <= 0; - else - readpointer <= readpointer + 1; - end if; - else - decrement_wd_cnt <= '0'; - readpointer <= readpointer; - end if; - end if; - end if; - end process read_proc; - - ReAddr_mem <= std_logic_vector(to_unsigned(readpointer, g_addresswidth)); - - word_counter_proc : process(clk) is - 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)); - 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; - end if; - end if; - end if; - end process word_counter_proc; - - throughput_proc : process (clk) is - begin - if rising_edge(clk) then - if rst = '1' then - ticks_counter <= (others => '0'); - inword_counter <= (others => '0'); - outword_counter <= (others => '0'); - else - if wr_en = '1' then - inword_counter <= inword_counter + 1; - end if; - if rd_en = '1' then - outword_counter <= outword_counter + 1; - end if; - if ticks_counter = g_clockspeed - 1 then - ticks_counter <= (others => '0'); - inword_counter <= (others => '0'); - outword_counter <= (others => '0'); - inword_freq <= std_logic_vector(inword_counter); - outword_freq <= std_logic_vector(outword_counter); - else - ticks_counter <= ticks_counter + 1; - end if; - end if; - 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 <= 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; - + + RAM_DP_4096_32_1: entity work.RAM_DP_4096_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; + + WrAddr_mem <= std_logic_vector(to_unsigned(writepointer, g_addresswidth)); + Din_mem <= data_in; + WrEn_mem <= wr_en_i; + + read_write_offset_proc : process(offset, writepointer) is + begin + read_write_pointer_offset <= writepointer - to_integer(unsigned(offset)) after 2 ns; + end process read_write_offset_proc; + + read_proc : process(clk) is + begin + if rising_edge(clk) then + if rst = '1' then + readpointer <= 0; + decrement_wd_cnt <= '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; + end if; + elsif rd_en_i = '1' then + decrement_wd_cnt <= '1'; + if readpointer = c_high_address - 1 then + readpointer <= 0; + else + readpointer <= readpointer + 1; + end if; + else + decrement_wd_cnt <= '0'; + readpointer <= readpointer; + end if; + end if; + end if; + end process read_proc; + + ReAddr_mem <= std_logic_vector(to_unsigned(readpointer, g_addresswidth)); + + word_counter_proc : process(clk) is + 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)); + 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; + end if; + end if; + end if; + end process word_counter_proc; + + throughput_proc : process (clk) is + begin + if rising_edge(clk) then + if rst = '1' then + ticks_counter <= (others => '0'); + inword_counter <= (others => '0'); + outword_counter <= (others => '0'); + else + if wr_en = '1' then + inword_counter <= inword_counter + 1; + end if; + if rd_en = '1' then + outword_counter <= outword_counter + 1; + end if; + if ticks_counter = g_clockspeed - 1 then + ticks_counter <= (others => '0'); + inword_counter <= (others => '0'); + outword_counter <= (others => '0'); + inword_freq <= std_logic_vector(inword_counter); + outword_freq <= std_logic_vector(outword_counter); + else + ticks_counter <= ticks_counter + 1; + end if; + end if; + 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 <= 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; + end architecture RTL; diff --git a/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd b/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd index 8c992e1..d242173 100644 --- a/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd +++ b/mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd @@ -9,9 +9,11 @@ use ieee.numeric_std.all; entity MupixTRBReadout is generic(g_mupix_links : natural := 4; -- number of input data channels from mupix - g_cyc_mem_address_width : integer := 13; -- memory depth of circular buffer + -- memory depth of circularbuffer (should match value of RAM in Circ Buffer) + g_cyc_mem_address_width : integer := 12; g_datawidthfifo : integer := 40; -- width of data words from fifos - g_datawidthtrb : integer := 32 -- trb data width + -- trb data width (should be 32 and match RAM in Circ Buffer) + g_datawidthtrb : integer := 32 ); port( clk : in std_logic; -- clock input diff --git a/mupix/Mupix8/tb/MupixTRBReadoutTest.vhd b/mupix/Mupix8/tb/MupixTRBReadoutTest.vhd index 7028334..2da3c20 100644 --- a/mupix/Mupix8/tb/MupixTRBReadoutTest.vhd +++ b/mupix/Mupix8/tb/MupixTRBReadoutTest.vhd @@ -57,7 +57,7 @@ architecture sim of MupixTRBReadoutTest is constant c_clk_period : time := 10 ns; constant c_mupix_links : integer := 4; - constant c_cyc_mem_address_width : integer := 6; + constant c_cyc_mem_address_width : integer := 12; constant c_datawidthfifo : integer := 40; constant c_datawidthtrb : integer := 32; diff --git a/mupix/Mupix8/trb3_periph.prj b/mupix/Mupix8/trb3_periph.prj index 1b9529c..75402e2 100644 --- a/mupix/Mupix8/trb3_periph.prj +++ b/mupix/Mupix8/trb3_periph.prj @@ -149,6 +149,7 @@ add_file -vhdl -lib "work" "cores/mupix_serdes_sim.vhd" add_file -vhdl -lib "work" "cores/serdes_fifo.vhd" add_file -vhdl -lib "work" "cores/mupix_sim_pll.vhd" add_file -vhdl -lib "work" "cores/fifo_sim.vhd" +add_file -vhdl -lib "work" "cores/RAM_DP_4096_32.vhd" #MuPix Files add_file -vhdl -lib "work" "trb3_periph.vhd" -- 2.43.0