]> jspc29.x-matter.uni-frankfurt.de Git - trb3.git/commitdiff
new version of circular buffer. needs testing in simulation and hardware.
authorTobias Weber <toweber86@gmail.com>
Wed, 12 Sep 2018 14:00:53 +0000 (16:00 +0200)
committerTobias Weber <toweber86@gmail.com>
Wed, 12 Sep 2018 15:35:56 +0000 (17:35 +0200)
mupix/Mupix8/sources/Datapath/CircularMemory.vhd
mupix/Mupix8/sources/Datapath/MupixTRBReadout.vhd
mupix/Mupix8/sources/Datapath/ReadoutController.vhd

index 143b2c6164e9e681555b616c66df7831d38febb7..21fe871157fae6facfdfc3dd75e501ff1dee43ac 100644 (file)
@@ -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;
index 79940c6f8b02912443e7920922f28ffba156f425..e0a7eda9858a1902836561c26407ddd1a1adc50a 100644 (file)
@@ -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';
index 3206e58900f20e8f51102a34f60247f6274bf41c..6c3cc35429f17f17e3c70c06c432fed0ed86fb88 100644 (file)
@@ -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;