]> jspc29.x-matter.uni-frankfurt.de Git - trb3.git/commitdiff
components related to mupix readout. Still Missing Serdes and trigger logic.
authorTobias Weber <toweber86@gmail.com>
Wed, 10 Jan 2018 10:41:23 +0000 (11:41 +0100)
committerTobias Weber <toweber86@gmail.com>
Wed, 10 Jan 2018 10:41:23 +0000 (11:41 +0100)
mupix/Mupix8/sources/CircularMemory.vhd
mupix/Mupix8/sources/MupixTRBReadout.vhd [new file with mode: 0644]
mupix/Mupix8/sources/ReadoutController.vhd [new file with mode: 0644]
mupix/Mupix8/tb/CircularMemoryTest.vhd
mupix/Mupix8/tb/MupixTRBReadoutTest.vhd [new file with mode: 0644]
mupix/Mupix8/tb/ReadoutControllerTest.vhd [new file with mode: 0644]

index 4544389df01685befe48ae5b575e1a7ab2bbf60b..eada2cc2463ebc1ae524b0e158a78c6045948d2b 100644 (file)
@@ -13,7 +13,8 @@ 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_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
@@ -21,10 +22,14 @@ entity CircularMemory is
                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
-               fillcnt      : out std_logic_vector(g_addresswidth - 1 downto 0); -- number of words in circular buffer
+               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
        );
@@ -48,21 +53,29 @@ architecture RTL of CircularMemory is
        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');
-       
+       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;
-               
+       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 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 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 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
        
@@ -84,62 +97,79 @@ begin
        begin
                if rising_edge(clk) then
                        if rst = '1' then
-                               writepointer <= 0;
+                               writepointer     <= 0;
+                               increment_wd_cnt <= '0';
                        else
-                               if wr_en = '1' then
-                                       WrAddr_mem <= std_logic_vector(to_unsigned(writepointer, g_addresswidth));
-                                       Din_mem    <= data_in;
-                                       WrEn_mem   <= '1';
+                               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;
-                                       WrAddr_mem   <= (others => '0');
-                                       Din_mem      <= (others => '0');
-                                       WrEn_mem     <= '0';
+                                       writepointer     <= writepointer;
+                                       increment_wd_cnt <= '0';
                                end if;
                        end if;
                end if;
        end process write_proc;
        
-       read_proc : process (clk) is
+       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;
+                               readpointer      <= 0;
+                               decrement_wd_cnt <= '0';
                        else
-                               if rd_en = '1' then
-                                       ReAddr_mem <= std_logic_vector(to_unsigned(readpointer, g_addresswidth));
+                               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
-                                       readpointer <= readpointer;
-                                       ReAddr_mem  <= (others => '0');
+                                       decrement_wd_cnt <= '0';
+                                       readpointer      <= readpointer;
                                end if;
                        end if;
                end if;
        end process read_proc;
        
-       word_counter_proc : process (clk) is
+       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 wr_en = '1' and rd_en = '0' then
+                               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 wr_en = '0' and rd_en = '1' then
+                               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
@@ -166,10 +196,10 @@ begin
                                end if;
                                if ticks_counter = g_clockspeed - 1 then
                                        ticks_counter <= (others => '0');
-                                       inword_freq <= std_logic_vector(inword_counter);
-                                       outword_freq <= std_logic_vector(outword_counter);
                                        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;
@@ -177,11 +207,16 @@ 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 <= '1' after 1 ns when words_in_buffer = 0 else '0' after 1 ns;
-       full  <= '1' after 1 ns when words_in_buffer = c_high_address else '0' after 1 ns;
-       fillcnt <= std_logic_vector(to_unsigned(words_in_buffer, g_addresswidth));
-       data_out <= Dout_mem;
+       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/MupixTRBReadout.vhd b/mupix/Mupix8/sources/MupixTRBReadout.vhd
new file mode 100644 (file)
index 0000000..910bac4
--- /dev/null
@@ -0,0 +1,366 @@
+-----------------------------------------------------------------------------------
+-- 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;
+
+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
+               g_datawidth             : integer := 32 -- width of data words
+              );
+       port(
+               clk                  : in  std_logic; -- clock input
+               rst                  : in  std_logic; -- reset input
+               -- input fifo signals (maybe we need word width conversion somewhere ?)
+               fifo_empty           : in  std_logic_vector(g_mupix_links - 1 downto 0);
+               fifo_full            : in  std_logic_vector(g_mupix_links - 1 downto 0);
+               fifo_datain          : in  std_logic_vector(g_mupix_links*g_datawidth - 1 downto 0);
+               fifo_rden            : out std_logic_vector(g_mupix_links - 1 downto 0);
+               -- readout and trigger
+               trb_trigger          : in  std_logic; -- signal from trb to start readout
+               dataout              : out std_logic_vector(g_datawidth - 1 downto 0); -- data to TRB data channel
+               data_valid           : out std_logic; -- output data is valid
+               busy                 : out std_logic; -- readout controller is busy
+               -- TRB slow Control channel
+               SLV_READ_IN          : in  std_logic;
+               SLV_WRITE_IN         : in  std_logic;
+               SLV_DATA_OUT         : out std_logic_vector(31 downto 0);
+               SLV_DATA_IN          : in  std_logic_vector(31 downto 0);
+               SLV_ADDR_IN          : in  std_logic_vector(15 downto 0);
+               SLV_ACK_OUT          : out std_logic;
+               SLV_NO_MORE_DATA_OUT : out std_logic;
+               SLV_UNKNOWN_ADDR_OUT : out std_logic);
+end entity MupixTRBReadout;
+
+
+architecture rtl of MupixTRBReadout is
+
+       component CircularMemory
+               generic(
+                       g_datawidth    : integer := 32;
+                       g_addresswidth : integer := 10;
+                       g_clockspeed   : integer := 1e8;
+                       g_boundedbuf   : boolean := false
+               );
+               port(
+                       clk          : in  std_logic;
+                       rst          : in  std_logic;
+                       wr_en        : in  std_logic;
+                       data_in      : in  std_logic_vector(g_datawidth - 1 downto 0);
+                       rd_en        : in  std_logic;
+                       offset_en    : in  std_logic;
+                       offset       : in  std_logic_vector(g_addresswidth - 1 downto 0);
+                       data_out     : out std_logic_vector(g_datawidth - 1 downto 0);
+                       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);
+                       inword_freq  : out std_logic_vector(31 downto 0);
+                       outword_freq : out std_logic_vector(31 downto 0)
+               );
+       end component CircularMemory;
+       
+       component FiFoDataMux
+               generic(
+                       g_datawidth  : integer := 32; 
+                       g_inputs     : integer := 4;
+                       g_clockspeed : integer := 1e8
+               );
+               port(
+                       clk         : in  std_logic;
+                       rst         : in  std_logic;
+                       fifo_empty  : in  std_logic_vector(g_inputs - 1 downto 0);
+                       fifo_full   : in  std_logic_vector(g_inputs - 1 downto 0);
+                       fifo_datain : in  std_logic_vector(g_inputs*g_datawidth - 1 downto 0);
+                       fifo_mask   : in  std_logic_vector(g_inputs - 1 downto 0);
+                       fifo_rden   : out std_logic_vector(g_inputs - 1 downto 0);
+                       buff_wren   : out std_logic;
+                       dataout     : out std_logic_vector(g_datawidth - 1 downto 0);
+                       wordin_freq : out std_logic_vector(32*g_inputs - 1 downto 0);
+                       fifo_full_o : out std_logic
+               );
+       end component FiFoDataMux;
+       
+       component ReadoutController
+               generic(
+                       g_datawidth    : integer := 32;
+                       g_addresswidth : integer := 10
+               );
+               port(
+                       clk               : in  std_logic;
+                       rst               : in  std_logic;
+                       start             : in  std_logic;
+                       mode              : in  std_logic_vector(1 downto 0);
+                       writes_after_trig : in  std_logic_vector(g_addresswidth - 1 downto 0);
+                       max_words         : in  std_logic_vector(g_addresswidth - 1 downto 0);
+                       data_in           : in  std_logic_vector(g_datawidth - 1 downto 0);
+                       empty             : in  std_logic;
+                       almost_empty      : in  std_logic;
+                       sensor_id         : in  std_logic_vector(g_datawidth - 1 downto 0);
+                       offset_en         : out std_logic;
+                       rd_en             : out std_logic;
+                       busy              : out std_logic;
+                       data_valid        : out std_logic;
+                       data_out          : out std_logic_vector(g_datawidth - 1 downto 0)
+               );
+       end component ReadoutController;
+       
+       signal readout_mode_i          : std_logic_vector(1 downto 0)                           := "00";
+       signal readout_writes_aft_trig : std_logic_vector(g_cyc_mem_address_width - 1 downto 0) := (others => '0');
+       signal readout_words           : std_logic_vector(g_cyc_mem_address_width - 1 downto 0) := (others => '0');
+       signal sensor_id               : std_logic_vector(31 downto 0)                          := (others => '0');
+       signal multiplexer_mask        : std_logic_vector(g_mupix_links - 1 downto 0)           := (others => '0');
+       signal multiplexer_channel_sel : integer range 0 to g_mupix_links - 1                   := 0;
+       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_inword_freq        : std_logic_vector(31 downto 0);
+       signal cycl_outword_freq       : std_logic_vector(31 downto 0);
+       signal cycl_empty              : std_logic;
+       signal cycl_full               : std_logic;
+       signal cycl_almost_empty       : std_logic;
+       
+       signal fifo_mux_wren     : std_logic;
+       signal fifo_mux_data_out : std_logic_vector(g_datawidth - 1 downto 0);
+       
+       signal start_readout_slow_to_buffer      : std_logic := '0';
+       signal start_readout                     : std_logic := '0';
+       signal readout_controller_data_in        : std_logic_vector(g_datawidth - 1 downto 0);
+       signal readout_controller_data_out       : std_logic_vector(g_datawidth - 1 downto 0);
+       signal readout_controller_busy           : std_logic;
+       signal readout_controller_offset_en      : std_logic;
+       signal readout_controller_rd_en          : std_logic;
+       signal readout_controller_data_valid     : std_logic;
+       
+       type slow_readout_fsm_type is (idle, waitstate);
+       signal slow_readout_fsm : slow_readout_fsm_type := idle;
+       signal slow_data        : std_logic_vector(g_datawidth - 1 downto 0) := (others => '0');
+       signal start_slow_read  : std_logic := '0';
+       signal slow_read_busy   : std_logic := '0';
+       signal slow_read_done   : std_logic := '0';
+       
+begin
+       
+       start_readout <= start_readout_slow_to_buffer or trb_trigger; 
+       
+       data_mux_1 : entity work.FiFoDataMux
+               generic map(
+                       g_datawidth  => g_datawidth,
+                       g_inputs     => g_mupix_links,
+                       g_clockspeed => 1e8
+               )
+               port map(
+                       clk         => clk,
+                       rst         => rst,
+                       fifo_empty  => fifo_empty,
+                       fifo_full   => fifo_full,
+                       fifo_datain => fifo_datain,
+                       fifo_mask   => multiplexer_mask,
+                       fifo_rden   => fifo_rden,
+                       buff_wren   => fifo_mux_wren,
+                       dataout     => fifo_mux_data_out,
+                       wordin_freq => wordin_freq,
+                       fifo_full_o => fifo_full_o
+               );
+       
+       cycl_buffer_1 : entity work.CircularMemory
+               generic map(
+                       g_datawidth    => g_datawidth,
+                       g_addresswidth => g_cyc_mem_address_width,
+                       g_clockspeed   => 1e8,
+                       g_boundedbuf   => false
+               )
+               port map(
+                       clk          => clk,
+                       rst          => rst,
+                       wr_en        => fifo_mux_wren,
+                       data_in      => fifo_mux_data_out,
+                       rd_en        => readout_controller_rd_en,
+                       offset_en    => readout_controller_offset_en,
+                       offset       => readout_words,
+                       data_out     => readout_controller_data_in,
+                       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
+               );
+       
+       readout_controller_1 : entity work.ReadoutController
+               generic map(
+                       g_datawidth    => g_datawidth,
+                       g_addresswidth => g_cyc_mem_address_width
+               )
+               port map(
+                       clk               => clk,
+                       rst               => rst,
+                       start             => start_readout,
+                       mode              => readout_mode_i,
+                       writes_after_trig => readout_writes_aft_trig,
+                       max_words         => readout_words,
+                       data_in           => readout_controller_data_in,
+                       empty             => cycl_empty,
+                       almost_empty      => cycl_almost_empty,
+                       sensor_id         => sensor_id,
+                       offset_en         => readout_controller_offset_en,
+                       rd_en             => readout_controller_rd_en,
+                       busy              => readout_controller_busy,
+                       data_valid        => readout_controller_data_valid,
+                       data_out          => readout_controller_data_out
+               );
+       
+       data_read_slow : process (clk) is
+       begin
+               if rising_edge(clk) then
+                       if rst = '1' then
+                               slow_readout_fsm             <= idle;
+                               slow_read_done               <= '0';
+                               slow_read_busy               <= '0';
+                               start_readout_slow_to_buffer <= '0';
+                       else
+                               start_readout_slow_to_buffer <= '0';
+                               slow_read_done   <= '0';
+                               case slow_readout_fsm is 
+                                       when idle =>
+                                               slow_readout_fsm <= idle;
+                                               slow_read_busy   <= '0';
+                                               if start_slow_read = '1' then
+                                                       start_readout_slow_to_buffer <= '1';
+                                                       slow_read_busy               <= '1';
+                                                       slow_data                    <= (others => '0');
+                                                       slow_readout_fsm             <= waitstate;
+                                               end if;
+                                       when waitstate =>
+                                               slow_read_busy <= '1';
+                                               if readout_controller_data_valid = '1' then
+                                                       slow_read_done   <= '1';
+                                                       slow_data        <= readout_controller_data_out;
+                                                       slow_readout_fsm <= idle;
+                                               end if;
+                               end case;
+                       end if;
+               end if;
+       end process data_read_slow;
+       
+       
+       ------------------------------------------------------------------------------------
+       --Slow Control Handling
+       ------------------------------------------------------------------------------------
+       --0x100: readout controller mode
+       --0x101: readout controller writes after trigger
+       --0x102: readout controller numbers of words to readout
+       --0x103: readout controller sensor id
+       --0x104: readout controller start slow readout (read only)
+       --0x105: fifo multiplexer mask
+       --0x106: fifo multiplexer input frequency (write select channel, read frequency)
+       --0x107: fifo multiplexer full (read-only)
+       --0x108: circular memory empty/full flags, fill cnt (read-only)
+       --0x109: circular memory input word frequency (read-only)
+       --0x10a: circular memory output word frequency (read-only)
+       -----------------------------------------------------------------------------------
+       slv_bus_handler : process(clk) is
+       begin
+               if rising_edge(clk) then
+                       if rst = '1' then
+                               SLV_DATA_OUT         <= (others => '0');
+                               SLV_ACK_OUT          <= '0';
+                               SLV_NO_MORE_DATA_OUT <= '0';
+                               SLV_UNKNOWN_ADDR_OUT <= '0';
+                               start_slow_read      <= '0';
+                       else
+                               SLV_DATA_OUT         <= (others => '0');
+                               SLV_ACK_OUT          <= '0';
+                               SLV_NO_MORE_DATA_OUT <= '0';
+                               SLV_UNKNOWN_ADDR_OUT <= '0';
+                               start_slow_read      <= '0';
+                               
+                               if slow_read_busy = '1' then
+                                       if slow_read_done = '1' then
+                                               SLV_DATA_OUT <= slow_data;
+                                               SLV_ACK_OUT  <= '1';
+                                       end if;
+                               
+                               elsif SLV_WRITE_IN = '1' then
+                                       case SLV_ADDR_IN is
+                                               when x"0100" =>
+                                                       readout_mode_i <= SLV_DATA_IN(1 downto 0);
+                                                       SLV_ACK_OUT    <= '1';
+                                               when x"0101" =>
+                                                       readout_writes_aft_trig <= SLV_DATA_IN(g_cyc_mem_address_width - 1 downto 0);
+                                                       SLV_ACK_OUT             <= '1';
+                                               when x"0102" =>
+                                                       readout_words           <= SLV_DATA_IN(g_cyc_mem_address_width - 1 downto 0);
+                                                       SLV_ACK_OUT             <= '1';
+                                               when x"0103" =>
+                                                       sensor_id   <= SLV_DATA_IN;
+                                                       SLV_ACK_OUT <= '1';
+                                               when x"0105" =>
+                                                       multiplexer_mask <= SLV_DATA_IN(g_mupix_links - 1 downto 0);
+                                                       SLV_ACK_OUT      <= '1';
+                                               when x"0106" =>
+                                                       multiplexer_channel_sel <= to_integer(unsigned(SLV_DATA_IN));
+                                                       SLV_ACK_OUT             <= '1';
+                                               when others =>
+                                                       slv_unknown_addr_out <= '1';
+                                       end case;
+                               elsif SLV_READ_IN = '1' then
+                                       case SLV_ADDR_IN is
+                                               when x"0100" =>
+                                                       SLV_DATA_OUT(1 downto 0) <= readout_mode_i;
+                                                       SLV_ACK_OUT              <= '1';
+                                               when x"0101" =>
+                                                       SLV_DATA_OUT(g_cyc_mem_address_width - 1 downto 0) <= readout_writes_aft_trig;
+                                                       SLV_ACK_OUT                                        <= '1';
+                                               when x"0102" =>
+                                                       SLV_DATA_OUT(g_cyc_mem_address_width - 1 downto 0) <= readout_words;
+                                                       SLV_ACK_OUT                                        <= '1';
+                                               when x"0103" =>
+                                                       SLV_DATA_OUT <= sensor_id;
+                                                       SLV_ACK_OUT  <= '1';
+                                               when x"0104" =>
+                                                       if cycl_empty = '0' and readout_mode_i = "00" then
+                                                               start_slow_read <= '1';
+                                                       else
+                                                               SLV_NO_MORE_DATA_OUT <= '1';
+                                                       end if;
+                                               when x"0105" =>
+                                                       SLV_DATA_OUT(g_mupix_links - 1 downto 0)       <= multiplexer_mask;
+                                                       SLV_ACK_OUT                                    <= '1';
+                                               when x"0106" =>
+                                                       SLV_DATA_OUT <= wordin_freq((multiplexer_channel_sel + 1)*32 - 1 downto multiplexer_channel_sel*32);
+                                                       SLV_ACK_OUT  <= '1';
+                                               when x"0107" =>
+                                                       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(g_cyc_mem_address_width + 1)      <= cycl_empty;
+                                                       SLV_DATA_OUT(g_cyc_mem_address_width + 2)      <= cycl_full;
+                                                       SLV_ACK_OUT                                    <= '1';
+                                               when x"0109" =>
+                                                       SLV_DATA_OUT <= cycl_inword_freq;
+                                                       SLV_ACK_OUT     <= '1';
+                                               when x"010a" =>
+                                                       SLV_DATA_OUT <= cycl_outword_freq;
+                                                       SLV_ACK_OUT     <= '1';
+                                               when others =>
+                                                       slv_unknown_addr_out <= '1';
+                                       end case;
+                               end if;
+                       end if;
+               end if;
+       end process slv_bus_handler;
+       
+       busy <= readout_controller_busy;
+       dataout <= readout_controller_data_out;
+       data_valid <= readout_controller_data_valid;
+       
+end architecture;
diff --git a/mupix/Mupix8/sources/ReadoutController.vhd b/mupix/Mupix8/sources/ReadoutController.vhd
new file mode 100644 (file)
index 0000000..c1e2016
--- /dev/null
@@ -0,0 +1,212 @@
+-----------------------------------------------------------------------------------
+-- 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 
+--           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
+--           note that full/empty flags are reset in this mode
+-----------------------------------------------------------------------------
+
+entity ReadoutController 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
+       );
+       port(
+               clk               : in  std_logic; -- clock 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)
+               max_words         : in  std_logic_vector(g_addresswidth - 1 downto 0); -- maximum number of words to read
+               data_in           : in  std_logic_vector(g_datawidth - 1 downto 0); -- data from buffer
+               empty             : in  std_logic; --empty flag from circular buffer
+               almost_empty      : in  std_logic; --empty flag from circular buffer
+               sensor_id         : in  std_logic_vector(g_datawidth - 1 downto 0);
+               offset_en         : out std_logic; -- set offset between read and write pointer (offset value is set directly in circular buffer)
+               rd_en             : out std_logic; -- read enable to circular buffer
+               busy              : out std_logic; -- readout controller busy
+               data_valid        : out std_logic; -- data from readout controller valid
+               data_out          : out std_logic_vector(g_datawidth - 1 downto 0)); -- data from readout controller
+end entity ReadoutController;
+
+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 
+       --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;
+
+       signal wordcounter        : unsigned(g_addresswidth - 1 downto 0) := (others => '0');
+       signal framecounter       : unsigned(31 downto 0)                 := (others => '0');
+       signal headercounter      : integer range 0 to 2                  := 0;
+       signal trailercounter     : integer range 0 to 1                  := 0;
+       signal triggerwaitcounter : unsigned(g_addresswidth - 1 downto 0) := (others => '0');
+       signal almost_empty_edge  : std_logic_vector(1 downto 0)          := (others => '0');
+
+begin
+
+       edge_detection : process (clk) is
+       begin
+               if rising_edge(clk) then
+                       if rst = '1' then
+                               almost_empty_edge <= (others => '0');
+                       else
+                               almost_empty_edge <= almost_empty_edge(0) & almost_empty;
+                       end if;
+               end if;
+       end process edge_detection;
+       
+
+       readout_proc : process(clk) is
+       begin
+               if rising_edge(clk) then
+                       if rst = '1' then
+                               readout_fsm   <= idle;
+                               rd_en         <= '0';
+                               busy          <= '0';
+                               data_valid    <= '0';
+                               data_out      <= (others => '0');
+                               framecounter  <= (others => '0');
+                               headercounter <= 0;
+                       else
+                               busy       <= '0';
+                               data_valid <= '0';
+                               data_out   <= (others => '0');
+                               rd_en      <= '0';
+                               offset_en  <= '0';
+                               case readout_fsm is
+                                       when idle =>
+                                               trailercounter     <= 0;
+                                               wordcounter        <= (others => '0');
+                                               headercounter      <= 0;
+                                               triggerwaitcounter <= (others => '0');
+                                               headercounter      <= 0;
+                                               if start = '1' then
+                                                       if mode = "00" then
+                                                               if empty = '0' then
+                                                                       readout_fsm <= read_single;
+                                                               else
+                                                                       data_out    <= (others => '0');
+                                                                       data_valid  <= '1';
+                                                                       readout_fsm <= idle;
+                                                               end if;
+                                                               busy <= '1';
+                                                       elsif mode = "01" then
+                                                               readout_fsm <= header;
+                                                               busy        <= '1';
+                                                       elsif mode = "10" then
+                                                               readout_fsm <= header;
+                                                               busy        <= '1';
+                                                       else
+                                                               readout_fsm <= idle;
+                                                       end if;
+                                               else
+                                                       readout_fsm <= idle;
+                                               end if;
+                                       when header =>
+                                               busy          <= '1';
+                                               data_valid    <= '1';
+                                               headercounter <= headercounter + 1;
+                                               case headercounter is
+                                                       when 0 =>
+                                                               data_out <= c_frame_start;
+                                                       when 1 =>
+                                                               data_out <= sensor_id;
+                                                       when 2 =>
+                                                               data_out     <= std_logic_vector(framecounter);
+                                                               framecounter <= framecounter + 1;
+                                                               if mode = "01" then
+                                                                       if empty = '0' then
+                                                                               readout_fsm <= wait_memory;
+                                                                               rd_en       <= '1';
+                                                                       else
+                                                                               readout_fsm <= trailer;
+                                                                       end if;
+                                                               else
+                                                                       readout_fsm <= wait_trigger;
+                                                               end if;
+                                               end case;
+                                       when read_single =>
+                                               data_valid  <= '1';
+                                               busy        <= '1';
+                                               rd_en       <= '1';
+                                               data_out    <= data_in;
+                                               readout_fsm <= idle;
+                                       when wait_memory =>
+                                               busy <= '1';
+                                               if empty = '0' then
+                                                       readout_fsm <= read;
+                                                       rd_en       <= '1';
+                                               else
+                                                       readout_fsm <= trailer;
+                                                       rd_en       <= '0';
+                                               end if;
+                                       when read =>
+                                               busy        <= '1';
+                                               data_valid  <= '1';
+                                           data_out    <= data_in;
+                                           wordcounter <= wordcounter + 1;
+                                               readout_fsm <= read;
+                                               if mode = "01" then
+                                                       if wordcounter < unsigned(max_words) - 2 and almost_empty = '0' then
+                                                               rd_en       <= '1';
+                                                       else
+                                                               rd_en <= '0';
+                                                       end if;
+                                                       if almost_empty_edge = "01" or wordcounter = unsigned(max_words) - 1 then
+                                                               readout_fsm <= trailer;
+                                                       end if;
+                                               else
+                                                       if wordcounter < unsigned(max_words) - 2 and almost_empty = '0' then
+                                                               rd_en       <= '1';
+                                                       else
+                                                               rd_en       <= '0';
+                                                       end if;
+                                                       if almost_empty_edge = "01" or wordcounter = unsigned(max_words) - 1 then
+                                                               readout_fsm <= trailer;
+                                                       end if;
+                                               end if;
+                                       when wait_trigger =>
+                                               busy        <= '1';
+                                               offset_en   <= '0';
+                                               triggerwaitcounter <= triggerwaitcounter + 1;
+                                               if triggerwaitcounter = unsigned(writes_after_trig) - 1 then
+                                                       if empty = '0' then
+                                                               readout_fsm <= wait_memory;
+                                                               rd_en       <= '1';
+                                                       else
+                                                               readout_fsm <= trailer;
+                                                       end if; 
+                                               end if;
+                                               if triggerwaitcounter = unsigned(writes_after_trig) - 2 then
+                                                       offset_en   <= '1';
+                                               end if;
+                                       when trailer =>
+                                               busy           <= '1';
+                                               data_valid     <= '1';
+                                               readout_fsm    <= trailer;
+                                               trailercounter <= trailercounter + 1;
+                                               if trailercounter = 0 then
+                                                       data_out(g_addresswidth - 1 downto 0) <= std_logic_vector(wordcounter);
+                                               else
+                                                       data_out    <= c_frame_end;
+                                                       readout_fsm <= idle;
+                                               end if;
+                               end case;
+                       end if;
+               end if;
+       end process readout_proc;
+
+end architecture RTL;
index 2388f99cbb6fe14134ceb7d32d4d0f998c18619b..1d2268fb60172d8a3a40066522d71da447f87cc0 100644 (file)
@@ -18,9 +18,13 @@ architecture sim of CircularMemoryTest is
                        wr_en    : in  std_logic;
                        data_in  : in  std_logic_vector(g_datawidth - 1 downto 0);
                        rd_en    : in  std_logic;
+                       offset_en : in  std_logic;  
+                       offset    : in  std_logic_vector(g_addresswidth - 1 downto 0);
                        data_out : out std_logic_vector(g_datawidth - 1 downto 0);
                        empty    : out std_logic;
+                       almost_empty : out std_logic;
                        full     : out std_logic;
+                       almost_full  : out std_logic;
                        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) 
@@ -36,10 +40,14 @@ architecture sim of CircularMemoryTest is
        signal wr_en    : std_logic := '0';
        signal data_in  : std_logic_vector(c_data_width - 1 downto 0) := (others => '0');
        signal rd_en    : std_logic := '0';
+       signal offset_en : std_logic := '0';
+       signal offset    : std_logic_vector(c_address_width - 1 downto 0) := (others => '0');
        signal data_out : std_logic_vector(c_data_width - 1 downto 0);
        signal empty    : std_logic;
+       signal almost_empty : std_logic;
        signal full     : std_logic;
-       signal fillcnt : std_logic_vector(c_address_width - 1 downto 0);
+       signal almost_full : std_logic;
+       signal fillcnt : std_logic_vector(c_address_width downto 0);
        signal inword_freq : std_logic_vector(31 downto 0);
        signal outword_freq : std_logic_vector(31 downto 0);
        
@@ -57,9 +65,13 @@ begin
                        wr_en    => wr_en,
                        data_in  => data_in,
                        rd_en    => rd_en,
+                       offset_en => offset_en,
+                       offset    => offset,
                        data_out => data_out,
                        empty    => empty,
+                       almost_empty => almost_empty,
                        full     => full,
+                       almost_full => almost_full,
                        fillcnt => fillcnt,
                        inword_freq => inword_freq,
                        outword_freq => outword_freq
@@ -76,18 +88,35 @@ begin
                stimulus : process is
                begin
                        wait for 100 ns;
-                       for i in 1 to 7 loop
+                       --general read/write test
+                       for i in 1 to 15 loop
                                wr_en <= '1';
                                data_in <= std_logic_vector(to_unsigned(i, c_data_width));
                                wait for c_clk_period;
                        end loop;
                        wr_en <= '0';
                        wait for 50 ns;
-                       for i in 1 to 7 loop
+                       for i in 1 to 9 loop
                                rd_en <= '1';
                                wait for c_clk_period;
                        end loop;
                        rd_en <= '0';
+                       --test offset for read pointer
+                       wait for 100 ns;
+                       offset <= std_logic_vector(to_unsigned(4, c_address_width));
+                       wait for c_clk_period;
+                       offset_en <= '1';
+                       wait for c_clk_period;
+                       offset_en <= '0';
+                       for i in 1 to 3 loop
+                               wr_en <= '1';
+                               data_in <= std_logic_vector(to_unsigned(i, c_data_width));
+                               wait for c_clk_period;
+                       end loop;
+                       wr_en <= '0';
+                       offset_en <= '1';
+                       wait for c_clk_period;
+                       offset_en <= '0';
                        wait;
                end process stimulus;
                
diff --git a/mupix/Mupix8/tb/MupixTRBReadoutTest.vhd b/mupix/Mupix8/tb/MupixTRBReadoutTest.vhd
new file mode 100644 (file)
index 0000000..67610f9
--- /dev/null
@@ -0,0 +1,178 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.TRBSimulationPkg.all;
+
+entity MupixTRBReadoutTest is
+end entity MupixTRBReadoutTest;
+
+architecture sim of MupixTRBReadoutTest is
+
+       component MupixTRBReadout
+               generic(
+                       g_mupix_links           : natural := 4;
+                       g_cyc_mem_address_width : integer := 13;
+                       g_datawidth             : integer := 32
+               );
+               port(
+                       clk                  : in  std_logic;
+                       rst                  : in  std_logic;
+                       fifo_empty           : in  std_logic_vector(g_mupix_links - 1 downto 0);
+                       fifo_full            : in  std_logic_vector(g_mupix_links - 1 downto 0);
+                       fifo_datain          : in  std_logic_vector(g_mupix_links*g_datawidth - 1 downto 0);
+                       fifo_rden            : out std_logic_vector(g_mupix_links - 1 downto 0);
+                       trb_trigger          : in  std_logic;
+                       dataout              : out std_logic_vector(g_datawidth - 1 downto 0);
+                       data_valid           : out std_logic;
+                       busy                 : out std_logic;
+                       SLV_READ_IN          : in  std_logic;
+                       SLV_WRITE_IN         : in  std_logic;
+                       SLV_DATA_OUT         : out std_logic_vector(31 downto 0);
+                       SLV_DATA_IN          : in  std_logic_vector(31 downto 0);
+                       SLV_ADDR_IN          : in  std_logic_vector(15 downto 0);
+                       SLV_ACK_OUT          : out std_logic;
+                       SLV_NO_MORE_DATA_OUT : out std_logic;
+                       SLV_UNKNOWN_ADDR_OUT : out std_logic
+               );
+       end component MupixTRBReadout;
+       
+       component STD_FIFO
+               generic(
+                       DATA_WIDTH : positive := 8;
+                       FIFO_DEPTH : positive := 256
+               );
+               port(
+                       CLK     : in  std_logic;
+                       RST     : in  std_logic;
+                       WriteEn : in  std_logic;
+                       DataIn  : in  std_logic_vector(DATA_WIDTH - 1 downto 0);
+                       ReadEn  : in  std_logic;
+                       DataOut : out std_logic_vector(DATA_WIDTH - 1 downto 0);
+                       Empty   : out std_logic;
+                       Full    : out std_logic
+               );
+       end component STD_FIFO;
+       
+       constant c_clk_period            : time    := 10 ns;
+       constant c_mupix_links           : integer := 4;
+       constant c_cyc_mem_address_width : integer := 6;
+       constant c_datawidth             : integer := 32;
+       
+       signal clk                       : std_logic;
+       signal rst                       : std_logic := '0';
+       signal fifo_empty                : std_logic_vector(c_mupix_links - 1 downto 0) := (others => '1');
+       signal fifo_full                 : std_logic_vector(c_mupix_links - 1 downto 0) := (others => '0');
+       signal fifo_data_to_mux          : std_logic_vector(c_mupix_links*c_datawidth - 1 downto 0) := (others => '0');
+       signal fifo_rden                 : std_logic_vector(c_mupix_links - 1 downto 0) := (others => '0');
+       signal trb_trigger               : std_logic := '0';
+       signal dataout                   : std_logic_vector(c_datawidth - 1 downto 0);
+       signal data_valid                : std_logic;
+       signal busy                      : std_logic;
+       signal SLV_READ_IN               : std_logic := '0';
+       signal SLV_WRITE_IN              : std_logic := '0';
+       signal SLV_DATA_OUT              : std_logic_vector(31 downto 0);
+       signal SLV_DATA_IN               : std_logic_vector(31 downto 0) := (others => '0');
+       signal SLV_ADDR_IN               : std_logic_vector(15 downto 0) := (others => '0');
+       signal SLV_ACK_OUT               : std_logic;
+       signal SLV_NO_MORE_DATA_OUT      : std_logic;
+       signal SLV_UNKNOWN_ADDR_OUT      : std_logic;
+       
+       signal fifo_write_en : std_logic_vector(c_mupix_links - 1 downto 0) := (others => '0');
+       signal fifo_datain   : std_logic_vector(c_mupix_links*c_datawidth - 1 downto 0) := (others => '0');
+       
+begin
+
+
+       dut : entity work.MupixTRBReadout
+               generic map(
+                       g_mupix_links           => c_mupix_links,
+                       g_cyc_mem_address_width => c_cyc_mem_address_width,
+                       g_datawidth             => c_datawidth
+               )
+               port map(
+                       clk                  => clk,
+                       rst                  => rst,
+                       fifo_empty           => fifo_empty,
+                       fifo_full            => fifo_full,
+                       fifo_datain          => fifo_data_to_mux,
+                       fifo_rden            => fifo_rden,
+                       trb_trigger          => trb_trigger,
+                       dataout              => dataout,
+                       data_valid           => data_valid,
+                       busy                 => busy,
+                       SLV_READ_IN          => SLV_READ_IN,
+                       SLV_WRITE_IN         => SLV_WRITE_IN,
+                       SLV_DATA_OUT         => SLV_DATA_OUT,
+                       SLV_DATA_IN          => SLV_DATA_IN,
+                       SLV_ADDR_IN          => SLV_ADDR_IN,
+                       SLV_ACK_OUT          => SLV_ACK_OUT,
+                       SLV_NO_MORE_DATA_OUT => SLV_NO_MORE_DATA_OUT,
+                       SLV_UNKNOWN_ADDR_OUT => SLV_UNKNOWN_ADDR_OUT
+               );
+       
+       gen_input_fifo : for i in 0 to 3 generate
+               input_fifo : entity work.STD_FIFO
+                       generic map(
+                               DATA_WIDTH => c_datawidth,
+                               FIFO_DEPTH => 16
+                       )
+                       port map(
+                               CLK     => CLK,
+                               RST     => RST,
+                               WriteEn => fifo_write_en(i),
+                               DataIn  => fifo_datain((i + 1)*c_datawidth - 1 downto i*c_datawidth),
+                               ReadEn  => fifo_rden(i),
+                               DataOut => fifo_data_to_mux((i + 1)*c_datawidth - 1 downto i*c_datawidth),
+                               Empty   => fifo_empty(i),
+                               Full    => fifo_full(i)
+                       );
+       end generate gen_input_fifo;
+       
+       
+       clock_gen : process is
+       begin
+               clk <= '1';
+               wait for c_clk_period/2;
+               clk <= '0';
+               wait for c_clk_period/2;
+       end process clock_gen;
+       
+       stimulus : process is
+       begin
+               wait for 100 ns;
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"0000000A", x"0101");
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"0000000B", x"0102");
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"ABBA0001", x"0103");
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"0000000F", x"0105");
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"00000000", x"0106");
+               wait for 5*c_clk_period;
+               for i in 1 to 10 loop
+                       fifo_write_en <= (others => '1');
+                       fifo_datain(4*32 - 1 downto 3*32) <= std_logic_vector(to_unsigned(i, c_datawidth));
+                       fifo_datain(3*32 - 1 downto 2*32) <= std_logic_vector(to_unsigned(i + 10, c_datawidth));
+                       fifo_datain(2*32 - 1 downto 1*32) <= std_logic_vector(to_unsigned(i + 20, c_datawidth));
+                       fifo_datain(1*32 - 1 downto 0*32) <= std_logic_vector(to_unsigned(i + 30, c_datawidth));
+                       wait for c_clk_period;
+               end loop;
+               fifo_write_en                     <= (others => '0');
+               fifo_datain(4*32 - 1 downto 3*32) <= (others => '0');
+               wait for 500 ns;
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"00000000", x"0100");
+               TRBRegisterRead(SLV_READ_IN, SLV_DATA_IN, SLV_ADDR_IN, x"00000000", x"0104");
+               if SLV_ACK_OUT = '0' then
+                       wait until slv_ack_out = '1';
+                       wait for c_clk_period;
+               end if;
+               TRBRegisterRead(SLV_READ_IN, SLV_DATA_IN, SLV_ADDR_IN, x"00000000", x"0104");
+               if SLV_ACK_OUT = '0' then
+                       wait until slv_ack_out = '1';
+                       wait for c_clk_period;
+               end if;
+               TRBRegisterWrite(SLV_WRITE_IN, SLV_DATA_IN, SLV_ADDR_IN, x"00000001", x"0100");
+               TRBRegisterRead(SLV_READ_IN, SLV_DATA_IN, SLV_ADDR_IN, x"00000000", x"0104");
+               wait;
+       end process stimulus;
+       
+       
+end architecture;
\ No newline at end of file
diff --git a/mupix/Mupix8/tb/ReadoutControllerTest.vhd b/mupix/Mupix8/tb/ReadoutControllerTest.vhd
new file mode 100644 (file)
index 0000000..a512454
--- /dev/null
@@ -0,0 +1,229 @@
+----------------------------------------------------------
+-- Test bench for Circular Memory Readout Controller
+-- Tobias Weber
+-- Ruhr Universtitaet Bochum
+----------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity ReadoutControllerTest is
+end entity ReadoutControllerTest;
+
+architecture sim of ReadoutControllerTest is
+
+constant c_datawidth : integer := 32;
+constant c_addresswidth : integer := 6;
+constant c_clockspeed : integer := 1e8;
+constant c_clk_period : time := 10 ns;
+
+component CircularMemory
+       generic(
+               g_datawidth    : integer := 32;
+               g_addresswidth : integer := 10;
+               g_clockspeed   : integer := 1e8
+       );
+       port(
+               clk          : in  std_logic;
+               rst          : in  std_logic;
+               wr_en        : in  std_logic;
+               data_in      : in  std_logic_vector(g_datawidth - 1 downto 0);
+               rd_en        : in  std_logic;
+               offset_en    : in  std_logic;
+               offset       : in  std_logic_vector(g_addresswidth - 1 downto 0);
+               data_out     : out std_logic_vector(g_datawidth - 1 downto 0);
+               empty        : out std_logic;
+               almost_empty : out  std_logic;
+               full         : out std_logic;
+               almost_full  : out std_logic;
+               fillcnt      : out std_logic_vector(g_addresswidth downto 0);
+               inword_freq  : out std_logic_vector(31 downto 0);
+               outword_freq : out std_logic_vector(31 downto 0)
+       );
+       end component CircularMemory;
+
+component ReadoutController
+       generic(
+               g_datawidth    : integer := 32;
+               g_addresswidth : integer := 10
+       );
+       port(
+               clk               : in  std_logic;
+               rst               : in  std_logic;
+               start             : in  std_logic;
+               mode              : in  std_logic_vector(1 downto 0);
+               writes_after_trig : in  std_logic_vector(g_addresswidth - 1 downto 0);
+               max_words         : in  std_logic_vector(g_addresswidth - 1 downto 0);
+               data_in           : in  std_logic_vector(g_datawidth - 1 downto 0);
+               empty             : in  std_logic;
+               almost_empty      : in  std_logic;
+               sensor_id         : in  std_logic_vector(g_datawidth - 1 downto 0);
+               offset_en         : out std_logic;
+               rd_en             : out std_logic;
+               busy              : out std_logic;
+               data_valid        : out std_logic;
+               data_out          : out std_logic_vector(g_datawidth - 1 downto 0)
+       );
+       end component ReadoutController;
+
+       signal clk               : std_logic;
+       signal rst               : std_logic                                     := '0';
+       signal wr_en             : std_logic                                     := '0';
+       signal data_in           : std_logic_vector(c_datawidth - 1 downto 0)    := (others => '0');
+       signal rd_en             : std_logic;
+       signal offset_en         : std_logic;
+       signal offset            : std_logic_vector(c_addresswidth - 1 downto 0);
+       signal data_out          : std_logic_vector(c_datawidth - 1 downto 0);
+       signal empty             : std_logic;
+       signal almost_empty      : std_logic;
+       signal full              : std_logic;
+       signal fillcnt           : std_logic_vector(c_addresswidth downto 0);
+       signal inword_freq       : std_logic_vector(31 downto 0);
+       signal outword_freq      : std_logic_vector(31 downto 0);
+       signal start             : std_logic                                     := '0';
+       signal mode              : std_logic_vector(1 downto 0)                  := (others => '0');
+       signal writes_after_trig : std_logic_vector(c_addresswidth - 1 downto 0) := (others => '0');
+       signal max_words         : std_logic_vector(c_addresswidth - 1 downto 0) := (others => '0');
+       signal sensor_id         : std_logic_vector(c_datawidth - 1 downto 0)    := (others => '0');
+       signal busy              : std_logic;
+       signal data_valid        : std_logic;
+       signal data_out_ctrl     : std_logic_vector(c_datawidth - 1 downto 0);
+
+begin
+       
+       memory : entity work.CircularMemory
+               generic map(
+                       g_datawidth    => c_datawidth,
+                       g_addresswidth => c_addresswidth,
+                       g_clockspeed   => c_clockspeed
+               )
+               port map(
+                       clk          => clk,
+                       rst          => rst,
+                       wr_en        => wr_en,
+                       data_in      => data_in,
+                       rd_en        => rd_en,
+                       offset_en    => offset_en,
+                       offset       => offset,
+                       data_out     => data_out,
+                       empty        => empty,
+                       almost_empty => almost_empty,
+                       full         => full,
+                       almost_full  => open,
+                       fillcnt      => fillcnt,
+                       inword_freq  => inword_freq,
+                       outword_freq => outword_freq
+               );
+       
+       controller : entity work.ReadoutController
+               generic map(
+                       g_datawidth    => c_datawidth,
+                       g_addresswidth => c_addresswidth
+               )
+               port map(
+                       clk               => clk,
+                       rst               => rst,
+                       start             => start,
+                       mode              => mode,
+                       writes_after_trig => writes_after_trig,
+                       max_words         => max_words,
+                       data_in           => data_out,
+                       empty             => empty,
+                       almost_empty      => almost_empty,
+                       sensor_id         => sensor_id,
+                       offset_en         => offset_en,
+                       rd_en             => rd_en,
+                       busy              => busy,
+                       data_valid        => data_valid,
+                       data_out          => data_out_ctrl
+               );
+       
+       clk_gen : process is
+       begin
+               clk <= '1';
+               wait for c_clk_period/2;
+               clk <= '0';
+               wait for c_clk_period/2;
+       end process clk_gen;
+       
+       stimulus : process is
+       begin
+               wait for 100 ns;
+               sensor_id         <= x"ABBA0001";
+               max_words         <= std_logic_vector(to_unsigned(10, c_addresswidth));
+               offset            <= std_logic_vector(to_unsigned(10, c_addresswidth));
+               writes_after_trig <= std_logic_vector(to_unsigned(4, c_addresswidth));
+               wait for c_clk_period/2;
+               
+               wait for c_clk_period;
+               --try reading from empty circular memory
+               start             <= '1';
+               wait for c_clk_period;
+               start             <= '0';
+               wait for 5*c_clk_period;
+               start             <= '1';
+               mode              <= "01";
+               wait for c_clk_period;
+               start             <= '0';
+               wait for 10*c_clk_period;
+               --fill the circular memory
+               for i in 1 to 22 loop
+                       wr_en   <= '1';
+                       data_in <= std_logic_vector(to_unsigned(i + 10, c_datawidth));
+                       wait for c_clk_period;
+               end loop;
+               wr_en   <= '0';
+               --try different read modes again
+               --read two single words
+               wait for c_clk_period;
+               start             <= '1';
+               mode              <= "00";
+               wait for c_clk_period;
+               start             <= '0';
+               wait for 5*c_clk_period;
+               start             <= '1';
+               wait for c_clk_period;
+               start             <= '0';
+               --read given number of words
+               wait for 5*c_clk_period;
+               start             <= '1';
+               mode              <= "01";
+               wait for c_clk_period;
+               start             <= '0';
+               if busy = '1' then
+                       wait until busy = '0';
+                       wait for 5*c_clk_period;
+               end if;
+               --read single word
+               mode              <= "00";
+               start             <= '1';
+               wait for c_clk_period;
+               start             <= '0';
+               wait for 5*c_clk_period;
+               --and read given number of words again
+               mode              <= "01";
+               start             <= '1';
+               wait for c_clk_period;
+               start             <= '0';
+               if busy = '1' then
+                       wait until busy = '0';
+                       wait for 5*c_clk_period;
+               end if;
+               wait for 50 ns;
+               -- trigger window test
+               for i in 1 to 78 loop
+                       wr_en   <= '1';
+                       data_in <= std_logic_vector(to_unsigned(i + 10, c_datawidth));
+                       wait for c_clk_period;
+               end loop;
+               wr_en   <= '0';
+               wait for 5*c_clk_period;
+               mode              <= "10";
+               start             <= '1';
+               wait for c_clk_period;
+               start             <= '0';
+               wait;
+       end process stimulus;
+       
+       
+end architecture sim;
\ No newline at end of file