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
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
);
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
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
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;
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;
--- /dev/null
+-----------------------------------------------------------------------------------
+-- 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;
--- /dev/null
+-----------------------------------------------------------------------------------
+-- 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;
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)
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);
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
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;
--- /dev/null
+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
--- /dev/null
+----------------------------------------------------------
+-- 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