From 7f22ec90502cae84564a7dcc209cafd9bb210ba9 Mon Sep 17 00:00:00 2001 From: Oliver Bruendler Date: Wed, 30 Oct 2019 11:02:11 +0100 Subject: [PATCH] BUGFIX: Made design working for 1 stream --- hdl/psi_ms_daq_daq_dma.vhd | 16 +- hdl/psi_ms_daq_daq_sm.vhd | 26 +- hdl/psi_ms_daq_reg_axi.vhd | 2 +- sim/config.tcl | 5 + tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb.vhd | 393 ++++++++++++++++++ .../psi_ms_daq_axi_1s_tb_str0_pkg.vhd | 258 ++++++++++++ 6 files changed, 682 insertions(+), 18 deletions(-) create mode 100644 tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb.vhd create mode 100644 tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb_str0_pkg.vhd diff --git a/hdl/psi_ms_daq_daq_dma.vhd b/hdl/psi_ms_daq_daq_dma.vhd index 3cb2c07..8ec2dcc 100644 --- a/hdl/psi_ms_daq_daq_dma.vhd +++ b/hdl/psi_ms_daq_daq_dma.vhd @@ -68,15 +68,19 @@ architecture rtl of psi_ms_daq_daq_dma is -- Constants constant BufferFifoDepth_c : integer := 32; + + -- Number of bits to encode stream is at least 1 (otherwise the special case for one stream would require separate code). + -- .. The overhead generated by this is regarded as aceptable (better wasting a few LUTs than much development time) + constant StreamBits_c : integer := max(log2ceil(Streams_g), 1); -- Component Connection Signals - signal CmdFifo_Level_Dbg : std_logic_vector(log2ceil(Streams_g) downto 0); + signal CmdFifo_Level_Dbg : std_logic_vector(StreamBits_c downto 0); signal CmdFifo_InData : std_logic_vector(DaqSm2DaqDma_Cmd_Size_c-1 downto 0); signal CmdFifo_OutData : std_logic_vector(DaqSm2DaqDma_Cmd_Size_c-1 downto 0); signal CmdFifo_Cmd : DaqSm2DaqDma_Cmd_t; signal CmdFifo_Vld : std_logic; - signal RspFifo_Level_Dbg : std_logic_vector(log2ceil(Streams_g) downto 0); + signal RspFifo_Level_Dbg : std_logic_vector(StreamBits_c downto 0); signal RspFifo_InData : std_logic_vector(DaqDma2DaqSm_Resp_Size_c-1 downto 0); signal RspFifo_OutData : std_logic_vector(DaqDma2DaqSm_Resp_Size_c-1 downto 0); signal DatFifo_Level_Dbg : std_logic_vector(log2ceil(BufferFifoDepth_c) downto 0); @@ -95,7 +99,7 @@ architecture rtl of psi_ms_daq_daq_dma is RspFifo_Vld : std_logic; RspFifo_Data : DaqDma2DaqSm_Resp_t; Mem_DataVld : std_logic; - StreamStdlv : std_logic_vector(log2ceil(Streams_g)-1 downto 0); + StreamStdlv : std_logic_vector(StreamBits_c-1 downto 0); RemWen : std_logic; RemWrBytes : std_logic_vector(2 downto 0); RemData : std_logic_vector(63 downto 0); @@ -300,7 +304,7 @@ begin i_fifocmd : entity work.psi_common_sync_fifo generic map ( Width_g => DaqSm2DaqDma_Cmd_Size_c, - Depth_g => Streams_g, + Depth_g => 2**StreamBits_c, RamStyle_g => "distributed", RamBehavior_g => "RBW" ) @@ -322,7 +326,7 @@ begin i_fiforsp : entity work.psi_common_sync_fifo generic map ( Width_g => DaqDma2DaqSm_Resp_Size_c, - Depth_g => Streams_g, + Depth_g => 2**StreamBits_c, RamStyle_g => "distributed", RamBehavior_g => "RBW" ) @@ -366,7 +370,7 @@ begin -- *** Remaining Data RAM *** i_remram : entity work.psi_common_sdp_ram generic map ( - Depth_g => Streams_g, + Depth_g => 2**StreamBits_c, Width_g => 1+1+3+64, IsAsync_g => false, RamStyle_g => "distributed", diff --git a/hdl/psi_ms_daq_daq_sm.vhd b/hdl/psi_ms_daq_daq_sm.vhd index a9d290e..68be9f7 100644 --- a/hdl/psi_ms_daq_daq_sm.vhd +++ b/hdl/psi_ms_daq_daq_sm.vhd @@ -76,6 +76,10 @@ end entity; ------------------------------------------------------------------------------ architecture rtl of psi_ms_daq_daq_sm is + -- Number of bits to encode stream is at least 1 (otherwise the special case for one stream would require separate code). + -- .. The overhead generated by this is regarded as aceptable (better wasting a few LUTs than much development time) + constant StreamBits_c : integer := max(log2ceil(Streams_g), 1); + -- Function Definitions function GetBitsOfStreamPrio( InputVector : std_logic_vector; Prio : integer) @@ -132,10 +136,10 @@ architecture rtl of psi_ms_daq_daq_sm is signal IrqFifoAlmFull : std_logic; signal IrqFifoEmpty : std_logic; signal IrqFifoGenIrq : std_logic; - signal IrqFifoStream : std_logic_vector(log2ceil(Streams_g)-1 downto 0); + signal IrqFifoStream : std_logic_vector(StreamBits_c-1 downto 0); signal IrqLastWinNr : std_logic_vector(log2ceil(Windows_g)-1 downto 0); - signal IrqFifoIn : std_logic_vector(log2ceil(Streams_g)+log2ceil(Windows_g) downto 0); - signal IrqFifoOut : std_logic_vector(log2ceil(Streams_g)+log2ceil(Windows_g) downto 0); + signal IrqFifoIn : std_logic_vector(StreamBits_c+log2ceil(Windows_g) downto 0); + signal IrqFifoOut : std_logic_vector(StreamBits_c+log2ceil(Windows_g) downto 0); -- Types type State_t is (Idle_s, CheckPrio1_s, CheckPrio2_s, CheckPrio3_s, CheckResp_s, TlastCheck_s, ReadCtxStr_s, First_s, ReadCtxWin_s, CalcAccess0_s, CalcAccess1_s, ProcResp0_s, NextWin_s, WriteCtx_s); @@ -178,7 +182,7 @@ architecture rtl of psi_ms_daq_daq_sm is HndlWinBytes : std_logic_vector(32 downto 0); HndlWinLast : std_logic_vector(31 downto 0); HndlTs : std_logic_vector(63 downto 0); - TfDoneCnt : std_logic_vector(log2ceil(Streams_g)-1 downto 0); + TfDoneCnt : std_logic_vector(StreamBits_c-1 downto 0); TfDoneReg : std_logic; HndlWinDone : std_logic; CtxStr_Cmd : ToCtxStr_t; @@ -681,15 +685,15 @@ begin -- *** IRQ Information FIFO *** -- input assembly - IrqFifoIn(log2ceil(Streams_g)-1 downto 0) <= std_logic_vector(to_unsigned(r.HndlStream, log2ceil(Streams_g))); - IrqFifoIn(log2ceil(Streams_g)+log2ceil(Windows_g)-1 downto log2ceil(Streams_g)) <= r.HndlLastWinNr; - IrqFifoIn(IrqFifoIn'high) <= r.HndlWinDone; + IrqFifoIn(StreamBits_c-1 downto 0) <= std_logic_vector(to_unsigned(r.HndlStream, StreamBits_c)); + IrqFifoIn(StreamBits_c+log2ceil(Windows_g)-1 downto StreamBits_c) <= r.HndlLastWinNr; + IrqFifoIn(IrqFifoIn'high) <= r.HndlWinDone; -- Instantiation i_irq_fifo : entity work.psi_common_sync_fifo generic map ( - Width_g => log2ceil(Streams_g)+log2ceil(Windows_g)+1, - Depth_g => Streams_g*4, + Width_g => StreamBits_c+log2ceil(Windows_g)+1, + Depth_g => 2**StreamBits_c*4, AlmFullOn_g => true, AlmFullLevel_g => Streams_g*3, RamStyle_g => "distributed" @@ -706,8 +710,8 @@ begin ); -- Output disassembly - IrqFifoStream <= IrqFifoOut(log2ceil(Streams_g)-1 downto 0); - IrqLastWinNr <= IrqFifoOut(log2ceil(Streams_g)+log2ceil(Windows_g)-1 downto log2ceil(Streams_g)); + IrqFifoStream <= IrqFifoOut(StreamBits_c-1 downto 0); + IrqLastWinNr <= IrqFifoOut(StreamBits_c+log2ceil(Windows_g)-1 downto StreamBits_c); IrqFifoGenIrq <= IrqFifoOut(IrqFifoOut'high); diff --git a/hdl/psi_ms_daq_reg_axi.vhd b/hdl/psi_ms_daq_reg_axi.vhd index cfb2203..40abbe0 100644 --- a/hdl/psi_ms_daq_reg_axi.vhd +++ b/hdl/psi_ms_daq_reg_axi.vhd @@ -206,7 +206,7 @@ begin v.Reg_Mode_Arm := (others => '0'); v.MaxLvlClr := (others => '0'); if AccAddr(15 downto 9) = X"0" & "001" then - Stream_v := to_integer(unsigned(AccAddr(8 downto 4))); + Stream_v := work.psi_common_math_pkg.min(to_integer(unsigned(AccAddr(8 downto 4))), Streams_g-1); -- MAXLVLn if AccAddr(3 downto 0) = X"0" then diff --git a/sim/config.tcl b/sim/config.tcl index 172b0f8..71edf1e 100644 --- a/sim/config.tcl +++ b/sim/config.tcl @@ -90,6 +90,8 @@ add_sources "../tb" { psi_ms_daq_axi/psi_ms_daq_axi_tb_str2_pkg.vhd \ psi_ms_daq_axi/psi_ms_daq_axi_tb_str3_pkg.vhd \ psi_ms_daq_axi/psi_ms_daq_axi_tb.vhd \ + psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb_str0_pkg.vhd \ + psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb.vhd \ } -tag tb #TB Runs @@ -112,6 +114,9 @@ add_tb_run create_tb_run "psi_ms_daq_axi_tb" add_tb_run +create_tb_run "psi_ms_daq_axi_1s_tb" +add_tb_run + diff --git a/tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb.vhd b/tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb.vhd new file mode 100644 index 0000000..33aaa76 --- /dev/null +++ b/tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb.vhd @@ -0,0 +1,393 @@ +------------------------------------------------------------------------------ +-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland +-- All rights reserved. +-- Authors: Oliver Bruendler +------------------------------------------------------------------------------ + +------------------------------------------------------------ +-- Testbench generated by TbGen.py +------------------------------------------------------------ +-- see Library/Python/TbGenerator + +------------------------------------------------------------ +-- Libraries +------------------------------------------------------------ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +library work; + use work.psi_common_math_pkg.all; + use work.psi_common_array_pkg.all; + use work.psi_ms_daq_pkg.all; + +library work; + use work.psi_tb_txt_util.all; + use work.psi_tb_compare_pkg.all; + use work.psi_tb_axi_pkg.all; + use work.psi_ms_daq_axi_tb_pkg.all; + use work.psi_ms_daq_axi_1s_tb_str0_pkg.all; + + +------------------------------------------------------------ +-- Entity Declaration +------------------------------------------------------------ +entity psi_ms_daq_axi_1s_tb is +end entity; + +------------------------------------------------------------ +-- Architecture +------------------------------------------------------------ +architecture sim of psi_ms_daq_axi_1s_tb is + + -- TB Control + signal TbRunning : boolean := true; + signal PrintIrq_c : boolean := PrintDefault_c; + + -- Constants + constant StrCount_c : integer := 1; + constant ClkFreq_c : t_areal := (0=>250.0e6); + + -- Axi Memory + constant ID_WIDTH : integer := 1; + constant ADDR_WIDTH : integer := 32; + constant USER_WIDTH : integer := 1; + constant DATA_WIDTH : integer := 64; + constant BYTE_WIDTH : integer := DATA_WIDTH/8; + + subtype ID_RANGE is natural range ID_WIDTH-1 downto 0; + subtype ADDR_RANGE is natural range ADDR_WIDTH-1 downto 0; + subtype USER_RANGE is natural range USER_WIDTH-1 downto 0; + subtype DATA_RANGE is natural range DATA_WIDTH-1 downto 0; + subtype BYTE_RANGE is natural range BYTE_WIDTH-1 downto 0; + + subtype axi_ms_t is axi_ms_r ( arid(ID_RANGE), awid(ID_RANGE), + araddr(ADDR_RANGE), awaddr(ADDR_RANGE), + aruser(USER_RANGE), awuser(USER_RANGE), wuser(USER_RANGE), + wdata(DATA_RANGE), + wstrb(BYTE_RANGE)); + + subtype axi_sm_t is axi_sm_r ( rid(ID_RANGE), bid(ID_RANGE), + ruser(USER_RANGE), buser(USER_RANGE), + rdata(DATA_RANGE)); + + -- Axi Registers + constant REG_ID_WIDTH : integer := 1; + constant REG_ADDR_WIDTH : integer := 16; + constant REG_USER_WIDTH : integer := 1; + constant REG_DATA_WIDTH : integer := 32; + constant REG_BYTE_WIDTH : integer := REG_DATA_WIDTH/8; + + subtype REG_ID_RANGE is natural range REG_ID_WIDTH-1 downto 0; + subtype REG_ADDR_RANGE is natural range REG_ADDR_WIDTH-1 downto 0; + subtype REG_USER_RANGE is natural range REG_USER_WIDTH-1 downto 0; + subtype REG_DATA_RANGE is natural range REG_DATA_WIDTH-1 downto 0; + subtype REG_BYTE_RANGE is natural range REG_BYTE_WIDTH-1 downto 0; + + subtype reg_axi_ms_t is axi_ms_r ( arid(REG_ID_RANGE), awid(REG_ID_RANGE), + araddr(REG_ADDR_RANGE), awaddr(REG_ADDR_RANGE), + aruser(REG_USER_RANGE), awuser(REG_USER_RANGE), wuser(REG_USER_RANGE), + wdata(REG_DATA_RANGE), + wstrb(REG_BYTE_RANGE)); + + subtype reg_axi_sm_t is axi_sm_r ( rid(REG_ID_RANGE), bid(REG_ID_RANGE), + ruser(REG_USER_RANGE), buser(REG_USER_RANGE), + rdata(REG_DATA_RANGE)); + + + -- Port signals + signal Str_Clk : std_logic_vector(StrCount_c-1 downto 0) := (others => '0'); + signal Str0_Data : std_logic_vector(7 downto 0) := (others => '0'); + signal Timestamp : t_aslv64(StrCount_c-1 downto 0) := (others => (others => '0')); + signal Str_Vld : std_logic_vector(StrCount_c-1 downto 0) := (others => '0'); + signal Str_Rdy : std_logic_vector(StrCount_c-1 downto 0) := (others => '0'); + signal Str_Trig : std_logic_vector(StrCount_c-1 downto 0) := (others => '0'); + signal M_Axi_Aclk : std_logic := '0'; + signal S_Axi_Aclk : std_logic := '0'; + signal M_Axi_Aresetn : std_logic := '0'; + signal S_Axi_Aresetn : std_logic := '0'; + signal Irq : std_logic := '0'; + signal axi_ms : axi_ms_t; + signal axi_sm : axi_sm_t; + signal reg_axi_ms : reg_axi_ms_t; + signal reg_axi_sm : reg_axi_sm_t; + + + procedure IrqHandler( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r) is + variable v : integer; + variable slv : std_logic_vector(31 downto 0); + begin + print("###################################### IRQ Detected #########################################", PrintIrq_c); + wait until rising_edge(clk); + AxiRead32(16#0010#, v, clk, rqst, rsp); + slv := std_logic_vector(to_unsigned(v, 32)); + AxiWrite32(16#0010#, v, clk, rqst, rsp); + wait until rising_edge(clk); + for i in 0 to StrCount_c-1 loop + if slv(i) = '1' then + case i is + when 0 => Str0Handler(clk, rqst, rsp); + when others => null; + end case; + end if; + end loop; + -- Delay to ensure IRQ is cleared + for i in 0 to 5 loop + wait until rising_edge(clk); + end loop; + end procedure; + + +begin + ------------------------------------------------------------ + -- DUT Instantiation + ------------------------------------------------------------ + i_dut : entity work.psi_ms_daq_axi + generic map ( + Streams_g => StrCount_c, + StreamWidth_g => (0=>8), + StreamPrio_g => (0=>1), + StreamBuffer_g => (0=>32), + StreamTimeout_g => (0=>5.0e-6), + StreamClkFreq_g => (ClkFreq_c, ClkFreq_c), + StreamTsFifoDepth_g => (0=>16, 1=>16), + StreamUseTs_g => (0=>true, 1=>true), + MaxWindows_g => work.psi_ms_daq_axi_tb_pkg.MaxWindows_c, + MinBurstSize_g => 16, + MaxBurstSize_g => 128, + AxiFifoDepth_g => 512, + AxiSlaveIdWidth_g => 1 + ) + port map ( + Str_Clk => Str_Clk, + Str_Data(0)(7 downto 0) => Str0_Data, + Str_Data(0)(63 downto 8) => (others => '0'), + Str_Ts => Timestamp, + Str_Vld => Str_Vld, + Str_Rdy => Str_Rdy, + Str_Trig => Str_Trig, + Irq => Irq, + S_Axi_Aclk => S_Axi_Aclk, + S_Axi_Aresetn => S_Axi_Aresetn, + S_Axi_ArId => reg_axi_ms.arid, + S_Axi_ArAddr => reg_axi_ms.araddr, + S_Axi_Arlen => reg_axi_ms.arlen, + S_Axi_ArSize => reg_axi_ms.arsize, + S_Axi_ArBurst => reg_axi_ms.arburst, + S_Axi_ArLock => reg_axi_ms.arlock, + S_Axi_ArCache => reg_axi_ms.arcache, + S_Axi_ArProt => reg_axi_ms.arprot, + S_Axi_ArValid => reg_axi_ms.arvalid, + S_Axi_ArReady => reg_axi_sm.arready, + S_Axi_RId => reg_axi_sm.rid, + S_Axi_RData => reg_axi_sm.rdata, + S_Axi_RResp => reg_axi_sm.rresp, + S_Axi_RLast => reg_axi_sm.rlast, + S_Axi_RValid => reg_axi_sm.rvalid, + S_Axi_RReady => reg_axi_ms.rready, + S_Axi_AwAddr => reg_axi_ms.awaddr, + S_AXi_AwId => reg_axi_ms.awid, + S_Axi_AwLen => reg_axi_ms.awlen, + S_Axi_AwSize => reg_axi_ms.awsize, + S_Axi_AwBurst => reg_axi_ms.awburst, + S_Axi_AwLock => reg_axi_ms.awlock, + S_Axi_AwCache => reg_axi_ms.awcache, + S_Axi_AwProt => reg_axi_ms.awprot, + S_Axi_AwValid => reg_axi_ms.awvalid, + S_Axi_AwReady => reg_axi_sm.awready, + S_Axi_WData => reg_axi_ms.wdata, + S_Axi_WStrb => reg_axi_ms.wstrb, + S_Axi_WLast => reg_axi_ms.wlast, + S_Axi_WValid => reg_axi_ms.wvalid, + S_Axi_WReady => reg_axi_sm.wready, + S_Axi_BId => reg_axi_sm.bid, + S_Axi_BResp => reg_axi_sm.bresp, + S_Axi_BValid => reg_axi_sm.bvalid, + S_Axi_BReady => reg_axi_ms.bready, + M_Axi_Aclk => M_Axi_Aclk, + M_Axi_Aresetn => M_Axi_Aresetn, + M_Axi_AwAddr => axi_ms.awaddr, + M_Axi_AwLen => axi_ms.awlen, + M_Axi_AwSize => axi_ms.awsize, + M_Axi_AwBurst => axi_ms.awburst, + M_Axi_AwLock => axi_ms.awlock, + M_Axi_AwCache => axi_ms.awcache, + M_Axi_AwProt => axi_ms.awprot, + M_Axi_AwValid => axi_ms.awvalid, + M_Axi_AwReady => axi_sm.awready, + M_Axi_WData => axi_ms.wdata, + M_Axi_WStrb => axi_ms.wstrb, + M_Axi_WLast => axi_ms.wlast, + M_Axi_WValid => axi_ms.wvalid, + M_Axi_WReady => axi_sm.wready, + M_Axi_BResp => axi_sm.bresp, + M_Axi_BValid => axi_sm.bvalid, + M_Axi_BReady => axi_ms.bready, + M_Axi_ArAddr => axi_ms.araddr, + M_Axi_ArLen => axi_ms.arlen, + M_Axi_ArSize => axi_ms.arsize, + M_Axi_ArBurst => axi_ms.arburst, + M_Axi_ArLock => axi_ms.arlock, + M_Axi_ArCache => axi_ms.arcache, + M_Axi_ArProt => axi_ms.arprot, + M_Axi_ArValid => axi_ms.arvalid, + M_Axi_ArReady => axi_sm.arready, + M_Axi_RData => axi_sm.rdata, + M_Axi_RResp => axi_sm.rresp, + M_Axi_RLast => axi_sm.rlast, + M_Axi_RValid => axi_sm.rvalid, + M_Axi_RReady => axi_ms.rready + ); + + ------------------------------------------------------------ + -- Emulate Memory + ------------------------------------------------------------ + p_mem : process + variable Address_v : integer; + variable Size_v : integer; + begin + axi_slave_init(axi_sm); + wait until rising_edge(M_Axi_Aclk); + while TbRunning loop + axi_sm.awready <= '1'; + wait until (rising_edge(M_Axi_Aclk) and axi_ms.awvalid = '1') or (not TbRunning); + if TbRunning then + axi_sm.awready <= '0'; + axi_sm.wready <= '1'; + Address_v := to_integer(unsigned(axi_ms.awaddr)); + Size_v := to_integer(unsigned(axi_ms.awlen))+1; + for qw in 0 to Size_v-1 loop + wait until rising_edge(M_Axi_Aclk) and axi_ms.wvalid = '1'; + for byte in 0 to 7 loop + if axi_ms.wstrb(byte) = '1' then + Memory(Address_v+qw*8+byte) <= axi_ms.wdata(byte*8+7 downto byte*8); + end if; + end loop; + end loop; + StdlCompare(1, axi_ms.wlast, "Last not received at end of burst"); + axi_sm.wready <= '0'; + axi_sm.bresp <= xRESP_OKAY_c; + axi_sm.bvalid <= '1'; + wait until rising_edge(M_Axi_Aclk) and axi_ms.bready = '1'; + axi_sm.bvalid <= '0'; + end if; + end loop; + wait; + end process; + + ------------------------------------------------------------ + -- Clocks + ------------------------------------------------------------ + + p_clk_axi_mem : process + constant Frequency_c : real := real(200e6); + begin + while TbRunning loop + wait for 0.5*(1 sec)/Frequency_c; + M_Axi_Aclk <= not M_Axi_Aclk; + end loop; + wait; + end process; + + p_clk_axi_reg : process + constant Frequency_c : real := real(166e6); + begin + while TbRunning loop + wait for 0.5*(1 sec)/Frequency_c; + S_Axi_Aclk <= not S_Axi_Aclk; + end loop; + wait; + end process; + + g_clk_str : for i in 0 to StrCount_c-1 generate + p_clk_str : process + begin + while TbRunning loop + wait for 0.5*(1 sec)/(ClkFreq_c(i)+0.1e6); + Str_Clk(i) <= not Str_Clk(i); + end loop; + wait; + end process; + end generate; + + ------------------------------------------------------------ + -- Reg-Access Process + ------------------------------------------------------------ + p_regacc : process + variable StartTime_v : time; + variable Stream1Armed_v : boolean := false; + variable Stream2Armed_v : boolean := false; + begin + print("*** Info ***"); + print("This testbench does not print any status information by default (only errors)."); + print("To change this behavior, change the constant PrintDefault_c in psi_ms_daq_axi_1s_tb_pkg."); + + axi_master_init(reg_axi_ms); + wait for 1 us; + S_Axi_Aresetn <= '1'; + M_Axi_Aresetn <= '1'; + + -- *** Initial Configuration *** + AxiExpect32(16#0010#, 0, S_Axi_Aclk, reg_axi_ms, reg_axi_sm, "Inital IRQVEC"); + AxiWriteAndRead32(16#0014#, 16#0001#, S_Axi_Aclk, reg_axi_ms, reg_axi_sm); + AxiWriteAndRead32(16#0020#, 16#0001#, S_Axi_Aclk, reg_axi_ms, reg_axi_sm); + -- Stream Setup + Str0Setup(S_Axi_Aclk, reg_axi_ms, reg_axi_sm); + + -- Enable + AxiWriteAndRead32(16#0000#, 16#0101#, S_Axi_Aclk, reg_axi_ms, reg_axi_sm); + + + -- *** Run Test *** + StartTime_v := now; + while now < StartTime_v+150 us loop + wait until rising_edge(S_Axi_Aclk); + -- IRQ Handling + if Irq = '1' then + IrqHandler(S_Axi_Aclk, reg_axi_ms, reg_axi_sm); + end if; + -- Regular actions + Str0Update(S_Axi_Aclk, reg_axi_ms, reg_axi_sm); + + end loop; + TbRunning <= false; + + -- *** Check end state *** + assert Str0WinCheck >= 4 report "###ERROR###: Stream 0 checks not completed" severity error; + wait; + end process; + + ------------------------------------------------------------ + -- Timestamp Processes + ------------------------------------------------------------ + g_ts : for i in 0 to StrCount_c-1 generate + p_ts : process + begin + while TbRunning loop + wait until rising_edge(Str_Clk(0)); + Timestamp(0) <= std_logic_vector(unsigned(Timestamp(0)) + 1); + end loop; + wait; + end process; + end generate; + + ------------------------------------------------------------ + -- Data Generation Processes + ------------------------------------------------------------ + p_str0 : process + variable IrqOn : boolean := false; + begin + wait until rising_edge(Str_Clk(0)); + while TbRunning loop + Str0Sample(Str_Clk(0), Str_Vld(0), Str_Trig(0), Str0_Data); + end loop; + wait; + end process; + + ------------------------------------------------------------ + -- Check Process + ------------------------------------------------------------ + +end; diff --git a/tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb_str0_pkg.vhd b/tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb_str0_pkg.vhd new file mode 100644 index 0000000..4284c44 --- /dev/null +++ b/tb/psi_ms_daq_axi_1s/psi_ms_daq_axi_1s_tb_str0_pkg.vhd @@ -0,0 +1,258 @@ +------------------------------------------------------------------------------ +-- Copyright (c) 2019 by Paul Scherrer Institute, Switzerland +-- All rights reserved. +-- Authors: Oliver Bruendler +------------------------------------------------------------------------------ + +------------------------------------------------------------ +-- Description +------------------------------------------------------------ +-- Stream 0 works in ringbuffer mode (without overwrite). It +-- produces 8-bit data (modulo counter). IRQs are located at samples +-- containing data 30, 60 and 90. IRQs are suppressed until 15 us after +-- simulation to see if IRQ enable works correctly. +-- The IRQ handler also sets the window sample counter to zero to ensure +-- more data can be recorded after the IRQ. + +------------------------------------------------------------ +-- Libraries +------------------------------------------------------------ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +library work; + use work.psi_common_math_pkg.all; + use work.psi_common_array_pkg.all; + use work.psi_ms_daq_pkg.all; + +library work; + use work.psi_tb_txt_util.all; + use work.psi_tb_compare_pkg.all; + use work.psi_ms_daq_axi_tb_pkg.all; + use work.psi_tb_axi_pkg.all; + +------------------------------------------------------------ +-- Package Header +------------------------------------------------------------ +package psi_ms_daq_axi_1s_tb_str0_pkg is + + constant PrintStr0_c : boolean := PrintDefault_c; + + -- Memory + constant Str0BufStart_c : integer := 16#1000#; + constant Str0WinSize_c : integer := 100; + constant Str0Windows_c : integer := 3; + alias Memory0 : t_aslv8(0 to Str0WinSize_c*Str0Windows_c) is Memory(Str0BufStart_c to Str0BufStart_c+Str0WinSize_c*Str0Windows_c); + + -------------------------------------------------------- + -- Persistent State + -------------------------------------------------------- + shared variable Str0NextWin : integer := 0; + shared variable Str0WinCheck : integer := 0; + shared variable Str0LastTs : integer; + shared variable Str0IrqOn : boolean := false; + shared variable Str0Disabled : boolean := false; + + -------------------------------------------------------- + -- Data Generation + -------------------------------------------------------- + procedure Str0Sample( signal clk : in std_logic; + signal vld : out std_logic; + signal trig : out std_logic; + signal data : out std_logic_vector(7 downto 0)); + + -------------------------------------------------------- + -- IRQ Handler + -------------------------------------------------------- + procedure Str0Handler( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r); + + -------------------------------------------------------- + -- Setup + -------------------------------------------------------- + procedure Str0Setup( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r); + + -------------------------------------------------------- + -- Update + -------------------------------------------------------- + procedure Str0Update( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r); + + +end package; + +------------------------------------------------------------ +-- Package Body +------------------------------------------------------------ +package body psi_ms_daq_axi_1s_tb_str0_pkg is + + -------------------------------------------------------- + -- Data Generation + -------------------------------------------------------- + procedure Str0Sample( signal clk : in std_logic; + signal vld : out std_logic; + signal trig : out std_logic; + signal data : out std_logic_vector(7 downto 0)) is + begin + vld <= '1'; + if (now > 15 us) and (to_integer(unsigned(data)) = 0) then + Str0IrqOn := true; + end if; + case to_integer(unsigned(data)) is + when 30 | 60 | 90 => + if Str0IrqOn then + trig <= '1'; + end if; + when others => null; + end case; + wait until rising_edge(clk); + vld <= '0'; + trig <= '0'; + data <= std_logic_vector(unsigned(data)+1); + wait until rising_edge(clk); + end procedure; + + -------------------------------------------------------- + -- IRQ Handler + -------------------------------------------------------- + procedure Str0Handler( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r) is + variable v : integer; + variable curwin : integer; + variable lastwin : integer; + variable wincnt : integer; + variable winstart, winend : integer; + variable winlast : integer; + variable addr : integer; + variable tslo : integer; + variable firstLoop : boolean := true; + variable HasTrigger : boolean; + begin + print("------------ Stream 0 Handler ------------", PrintStr0_c); + HlGetMaxLvl(0, clk, rqst, rsp, v); + print("MAXLVL: " & to_string(v), PrintStr0_c); + HlGetCurWin(0, clk, rqst, rsp, curwin); + print("CURWIN: " & to_string(curwin), PrintStr0_c); + HlGetLastWin(0, clk, rqst, rsp, lastwin); + print("LASTWIN: " & to_string(lastwin), PrintStr0_c); + print("", PrintStr0_c); + if Str0Disabled then + print("Skipped, stream disabled", PrintStr0_c); + print("", PrintStr0_c); + else + HlIsTrigWin(0, Str0NextWin, clk, rqst, rsp, HasTrigger); + -- lastwin = nextwin can occur if al lwindows are filled. In all cases we only interpret windows containing triggers. + while ((Str0NextWin /= ((lastwin+1) mod 3)) or firstLoop) and HasTrigger loop + firstLoop := false; + print("*** Window " & to_string(Str0NextWin) & " / Number: " & to_string(Str0WinCheck) & " ***", PrintStr0_c); + HlGetWinCnt(0, Str0NextWin, clk, rqst, rsp, wincnt); + print("WINCNT: " & to_string(wincnt), PrintStr0_c); + HlClrWinCnt(0, Str0NextWin, clk, rqst, rsp); + HlGetWinLast(0, Str0NextWin, clk, rqst, rsp, winlast); + print("WINLAST: " & to_string(winlast), PrintStr0_c); + HlGetTsLo(0, Str0NextWin, clk, rqst, rsp, tslo); + print("WINTSLO: " & to_string(tslo), PrintStr0_c); + HlGetTsHi(0, Str0NextWin, clk, rqst, rsp, v); + print("WINTSHI: " & to_string(v), PrintStr0_c); + winstart := Str0BufStart_c + Str0NextWin*Str0WinSize_c; + winend := winstart + Str0WinSize_c - 1; + case Str0WinCheck is + when 0 => + -- Windows full because dat received for quite some time + IntCompare(Str0WinSize_c, wincnt, "Stream0: WINCNT wrong"); + -- Check Values + addr := winlast; + + for i in 256+30+3-99 to 256+30+3 loop + if addr = winend then + addr := winstart; + else + addr := addr + 1; + end if; + StdlvCompareInt (i mod 256, Memory(addr), "Stream0: Wrong value at 0x" & to_hstring(to_unsigned(addr,32)), false); + end loop; + + when 1 => + -- Trigger following each other with 30 samples difference + IntCompare(30, wincnt, "Stream0: WINCNT wrong"); + IntCompare(30*2, tslo-Str0LastTs, "Stream0: TS difference wrong"); + -- Check Values + addr := winstart; + for i in 34 to 63 loop + StdlvCompareInt (i, Memory(addr), "Stream0: Wrong value", false); + addr := addr + 1; -- does never wrap + end loop; + + when 2 => + -- Trigger following each other with 30 samples difference + IntCompare(30, wincnt, "Stream0: WINCNT wrong"); + IntCompare(30*2, tslo-Str0LastTs, "Stream0: TS difference wrong"); + -- Check Values + addr := winstart; + for i in 64 to 93 loop + StdlvCompareInt (i, Memory(addr), "Stream0: Wrong value", false); + addr := addr + 1; -- does never wrap + end loop; + when 3 => + -- Full buffer recorded after emptying first buffer + IntCompare(100, wincnt, "Stream0: WINCNT wrong"); + IntCompare((256-2*30)*2, tslo-Str0LastTs, "Stream0: TS difference wrong"); + -- Disable stream IRQ + AxiRead32(REG_CONF_IRQENA_ADDR, v, clk, rqst, rsp); + v := IntAnd(v, 16#0FE#); + AxiWrite32(REG_CONF_IRQENA_ADDR, v, clk, rqst, rsp); + AxiRead32(REG_CONF_STRENA_ADDR, v, clk, rqst, rsp); + v := IntAnd(v, 16#0FE#); + AxiWrite32(REG_CONF_STRENA_ADDR, v, clk, rqst, rsp); + Str0Disabled := true; + -- Check Values + addr := winlast + 1; + for i in 256+30+3-99 to 256+30+3 loop + StdlvCompareInt (i mod 256, Memory(addr), "Stream0: Wrong value", false); + if addr = winend then + addr := winstart; + else + addr := addr + 1; + end if; + end loop; + + when others => null; + end case; + print("", PrintStr0_c); + Str0LastTs := tslo; + Str0NextWin := (Str0NextWin + 1) mod 3; + Str0WinCheck := Str0WinCheck + 1; + end loop; + end if; + end procedure; + + -------------------------------------------------------- + -- Setup + -------------------------------------------------------- + procedure Str0Setup( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r) is + begin + HlCheckMaxLvl(0, 0, clk, rqst, rsp); + HlSetPostTrig(0, 3, clk, rqst, rsp); + HlSetMode(0, VAL_MODE_RECM_CONT, clk, rqst, rsp); + HlConfStream( str => 0, bufstart => Str0BufStart_c, ringbuf => true, overwrite => false, wincnt => Str0Windows_c, winsize => Str0WinSize_c, + clk => clk, rqst => rqst, rsp => rsp); + end procedure; + + -------------------------------------------------------- + -- Update + -------------------------------------------------------- + procedure Str0Update( signal clk : in std_logic; + signal rqst : out axi_ms_r; + signal rsp : in axi_sm_r) is + begin + end; + +end;