diff --git a/protocols/event-frame-sequencer/rtl/EventFrameSequencerDemux.vhd b/protocols/event-frame-sequencer/rtl/EventFrameSequencerDemux.vhd index 0a6edfd4ee..fc969926d5 100755 --- a/protocols/event-frame-sequencer/rtl/EventFrameSequencerDemux.vhd +++ b/protocols/event-frame-sequencer/rtl/EventFrameSequencerDemux.vhd @@ -68,6 +68,7 @@ architecture rtl of EventFrameSequencerDemux is seqCnt : slv(15 downto 0); dataCnt : Slv32Array(NUM_MASTERS_G-1 downto 0); dropCnt : slv(31 downto 0); + simDebug : slv(7 downto 0); index : natural range 0 to NUM_MASTERS_G-1; tUserFirst : slv(7 downto 0); tDest : slv(7 downto 0); @@ -90,6 +91,7 @@ architecture rtl of EventFrameSequencerDemux is seqCnt => (others => '0'), dataCnt => (others => (others => '0')), dropCnt => (others => '0'), + simDebug => (others => '0'), index => 0, tUserFirst => (others => '0'), tDest => (others => '0'), @@ -132,13 +134,15 @@ begin variable v : RegType; variable axilEp : AxiLiteEndPointType; variable validHdr : sl; - variable dbg : slv(7 downto 0); + variable sofDet : sl; + variable dbg : slv(7 downto 0); begin -- Latch the current value v := r; -- Update the local variable - dbg := x"00"; + v.simDebug := (others => '0'); + dbg := (others => '0'); if (v.state = IDLE_S) then dbg(0) := '0'; else @@ -203,29 +207,35 @@ begin -- Check for SOF validHdr := ssiGetUserSof(AXIS_CONFIG_G, rxMaster); + sofDet := ssiGetUserSof(AXIS_CONFIG_G, rxMaster); -- Check for EOF if (rxMaster.tLast = '1') then - validHdr := '0'; + validHdr := '0'; + v.simDebug(0) := ite(r.state = IDLE_S, sofDet, '0'); end if; -- Check for valid version field if (rxMaster.tData(7 downto 0) /= x"01") then - validHdr := '0'; + validHdr := '0'; + v.simDebug(1) := ite(r.state = IDLE_S, sofDet, '0'); end if; if (rxMaster.tData(15 downto 8) >= NUM_MASTERS_G) then - validHdr := '0'; + validHdr := '0'; + v.simDebug(2) := ite(r.state = IDLE_S, sofDet, '0'); end if; -- Check for valid event frame index - if (rxMaster.tData(24 downto 16) /= r.frameCnt) then - validHdr := '0'; + if (rxMaster.tData(23 downto 16) /= r.frameCnt) then + validHdr := '0'; + v.simDebug(3) := ite(r.state = IDLE_S, sofDet, '0'); end if; -- Check for valid event frame index if (rxMaster.tData(63 downto 48) /= r.seqCnt) then - validHdr := '0'; + validHdr := '0'; + v.simDebug(4) := ite(r.state = IDLE_S, sofDet, '0'); end if; -- State machine @@ -309,14 +319,19 @@ begin -- Check for state transitioning from MOVE_S to IDLE_S if (r.state = MOVE_S) and (v.state = IDLE_S) then - -- Increment frame counter + -- Increment counters v.frameCnt := r.frameCnt + 1; - v.seqCnt := r.seqCnt + 1; v.dataCnt(r.index) := r.dataCnt(r.index) + 1; -- Check if reseting frame counters if (r.numFrames = r.frameCnt) then + + -- Increment counter + v.seqCnt := r.seqCnt + 1; + + -- Reset the counter v.frameCnt := (others => '0'); + end if; end if; diff --git a/protocols/event-frame-sequencer/rtl/EventFrameSequencerMux.vhd b/protocols/event-frame-sequencer/rtl/EventFrameSequencerMux.vhd index 2ee9d834c5..333fe98e31 100755 --- a/protocols/event-frame-sequencer/rtl/EventFrameSequencerMux.vhd +++ b/protocols/event-frame-sequencer/rtl/EventFrameSequencerMux.vhd @@ -394,24 +394,24 @@ begin -- HEADER context v.txMaster.tData(7 downto 0) := x"01"; -- Version Field - v.txMaster.tData(15 downto 8) := toSlv(r.index, 8); -- MUX Index + v.txMaster.tData(15 downto 8) := toSlv(r.index, 8); -- MUX Index v.txMaster.tData(23 downto 16) := r.frameCnt; -- Event frame index v.txMaster.tData(31 downto 24) := r.numFrames; -- Event frame Size (zero inclusive) v.txMaster.tData(39 downto 32) := rxMasters(r.index).tUser(7 downto 0); -- TUSER_FIRST v.txMaster.tData(47 downto 40) := rxMasters(r.index).tDest; -- TDEST v.txMaster.tData(63 downto 48) := r.seqCnt; -- Sequence Counter - -- Increment frame counter - if (r.accept(r.index) = '1') then - v.frameCnt := r.frameCnt + 1; - end if; - -- Check for the last transfer elsif (rxMasters(r.index).tLast = '1') then -- Rearm the flag v.sof := '1'; + -- Increment frame counter + if (r.accept(r.index) = '1') then + v.frameCnt := r.frameCnt + 1; + end if; + -- Check for last channel if (r.index = NUM_SLAVES_G-1) then -- Next state diff --git a/protocols/event-frame-sequencer/ruckus.tcl b/protocols/event-frame-sequencer/ruckus.tcl index e3e79e21f3..7e52f14a5b 100755 --- a/protocols/event-frame-sequencer/ruckus.tcl +++ b/protocols/event-frame-sequencer/ruckus.tcl @@ -3,3 +3,6 @@ source $::env(RUCKUS_PROC_TCL) # Load Source Code loadSource -lib surf -dir "$::DIR_PATH/rtl" + +# Load Simulation +loadSource -lib surf -sim_only -dir "$::DIR_PATH/tb" diff --git a/protocols/event-frame-sequencer/tb/EventFrameSequencerTb.vhd b/protocols/event-frame-sequencer/tb/EventFrameSequencerTb.vhd new file mode 100755 index 0000000000..081441fa69 --- /dev/null +++ b/protocols/event-frame-sequencer/tb/EventFrameSequencerTb.vhd @@ -0,0 +1,365 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: surf.EventFrameSequencerMux/surf.EventFrameSequencerDemux cocoTB testbed +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_unsigned.all; + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiLitePkg.all; +use surf.AxiStreamPkg.all; + +entity EventFrameSequencerTb is + generic ( + -- AXI Stream Configuration + TUSER_WIDTH_G : positive range 8 to 8 := 8; + TID_WIDTH_G : positive range 8 to 8 := 8; + TDEST_WIDTH_G : positive range 8 to 8 := 8; + TDATA_NUM_BYTES_G : positive range 8 to 128 := 8); + port ( + -- Clock and Reset + AXIS_ACLK : in std_logic := '0'; + AXIS_ARESETN : in std_logic := '0'; + -- IP Integrator Slave AXI Stream Interface + S_AXIS0_TVALID : in std_logic := '0'; + S_AXIS0_TDATA : in std_logic_vector((8*TDATA_NUM_BYTES_G)-1 downto 0) := (others => '0'); + S_AXIS0_TSTRB : in std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0) := (others => '0'); + S_AXIS0_TKEEP : in std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0) := (others => '0'); + S_AXIS0_TLAST : in std_logic := '0'; + S_AXIS0_TDEST : in std_logic_vector(TDEST_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS0_TID : in std_logic_vector(TID_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS0_TUSER : in std_logic_vector(TUSER_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS0_TREADY : out std_logic; + -- IP Integrator Slave AXI Stream Interface + S_AXIS1_TVALID : in std_logic := '0'; + S_AXIS1_TDATA : in std_logic_vector((8*TDATA_NUM_BYTES_G)-1 downto 0) := (others => '0'); + S_AXIS1_TSTRB : in std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0) := (others => '0'); + S_AXIS1_TKEEP : in std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0) := (others => '0'); + S_AXIS1_TLAST : in std_logic := '0'; + S_AXIS1_TDEST : in std_logic_vector(TDEST_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS1_TID : in std_logic_vector(TID_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS1_TUSER : in std_logic_vector(TUSER_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS1_TREADY : out std_logic; + -- IP Integrator Master AXI Stream Interface + M_AXIS0_TVALID : out std_logic; + M_AXIS0_TDATA : out std_logic_vector((8*TDATA_NUM_BYTES_G)-1 downto 0); + M_AXIS0_TSTRB : out std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0); + M_AXIS0_TKEEP : out std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0); + M_AXIS0_TLAST : out std_logic; + M_AXIS0_TDEST : out std_logic_vector(TDEST_WIDTH_G-1 downto 0); + M_AXIS0_TID : out std_logic_vector(TID_WIDTH_G-1 downto 0); + M_AXIS0_TUSER : out std_logic_vector(TUSER_WIDTH_G-1 downto 0); + M_AXIS0_TREADY : in std_logic; + -- IP Integrator Master AXI Stream Interface + M_AXIS1_TVALID : out std_logic; + M_AXIS1_TDATA : out std_logic_vector((8*TDATA_NUM_BYTES_G)-1 downto 0); + M_AXIS1_TSTRB : out std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0); + M_AXIS1_TKEEP : out std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0); + M_AXIS1_TLAST : out std_logic; + M_AXIS1_TDEST : out std_logic_vector(TDEST_WIDTH_G-1 downto 0); + M_AXIS1_TID : out std_logic_vector(TID_WIDTH_G-1 downto 0); + M_AXIS1_TUSER : out std_logic_vector(TUSER_WIDTH_G-1 downto 0); + M_AXIS1_TREADY : in std_logic; + -- AXI-Lite Interface + S_AXIL_AWADDR : in std_logic_vector(31 downto 0); + S_AXIL_AWPROT : in std_logic_vector(2 downto 0); + S_AXIL_AWVALID : in std_logic; + S_AXIL_AWREADY : out std_logic; + S_AXIL_WDATA : in std_logic_vector(31 downto 0); + S_AXIL_WSTRB : in std_logic_vector(3 downto 0); + S_AXIL_WVALID : in std_logic; + S_AXIL_WREADY : out std_logic; + S_AXIL_BRESP : out std_logic_vector(1 downto 0); + S_AXIL_BVALID : out std_logic; + S_AXIL_BREADY : in std_logic; + S_AXIL_ARADDR : in std_logic_vector(31 downto 0); + S_AXIL_ARPROT : in std_logic_vector(2 downto 0); + S_AXIL_ARVALID : in std_logic; + S_AXIL_ARREADY : out std_logic; + S_AXIL_RDATA : out std_logic_vector(31 downto 0); + S_AXIL_RRESP : out std_logic_vector(1 downto 0); + S_AXIL_RVALID : out std_logic; + S_AXIL_RREADY : in std_logic); +end EventFrameSequencerTb; + +architecture mapping of EventFrameSequencerTb is + + constant TPD_C : time := 3 ns; + + constant AXIS_CONFIG_C : AxiStreamConfigType := ( + TSTRB_EN_C => true, + TDATA_BYTES_C => TDATA_NUM_BYTES_G, + TDEST_BITS_C => TDEST_WIDTH_G, + TID_BITS_C => TID_WIDTH_G, + TKEEP_MODE_C => TKEEP_COMP_C, + TUSER_BITS_C => TUSER_WIDTH_G, + TUSER_MODE_C => TUSER_FIRST_LAST_C); + + constant AXIL_CONFIG_C : AxiLiteCrossbarMasterConfigArray(1 downto 0) := genAxiLiteConfig(2, x"0000_0000", 20, 16); + + signal axilReadMaster : AxiLiteReadMasterType; + signal axilReadSlave : AxiLiteReadSlaveType; + signal axilWriteMaster : AxiLiteWriteMasterType; + signal axilWriteSlave : AxiLiteWriteSlaveType; + + signal axilReadMasters : AxiLiteReadMasterArray(1 downto 0); + signal axilReadSlaves : AxiLiteReadSlaveArray(1 downto 0); + signal axilWriteMasters : AxiLiteWriteMasterArray(1 downto 0); + signal axilWriteSlaves : AxiLiteWriteSlaveArray(1 downto 0); + + signal axisClk : sl := '0'; + signal axisRst : sl := '0'; + + signal sAxisMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal sAxisSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); + + signal axisMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal axisSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal mAxisMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal mAxisSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); + +begin + + --------------------------------------------------------------------------- + -- Adding Shim Layers for translating between cocoTB and local record types + --------------------------------------------------------------------------- + U_ShimLayerSlave_0 : entity surf.SlaveAxiStreamIpIntegrator + generic map ( + INTERFACENAME => "S_AXIS", + HAS_TLAST => 1, + HAS_TKEEP => 1, + HAS_TSTRB => 1, + HAS_TREADY => 1, + TUSER_WIDTH => TUSER_WIDTH_G, + TID_WIDTH => TID_WIDTH_G, + TDEST_WIDTH => TDEST_WIDTH_G, + TDATA_NUM_BYTES => TDATA_NUM_BYTES_G) + port map ( + -- IP Integrator AXI Stream Interface + S_AXIS_ACLK => AXIS_ACLK, + S_AXIS_ARESETN => AXIS_ARESETN, + S_AXIS_TVALID => S_AXIS0_TVALID, + S_AXIS_TDATA => S_AXIS0_TDATA, + S_AXIS_TSTRB => S_AXIS0_TSTRB, + S_AXIS_TKEEP => S_AXIS0_TKEEP, + S_AXIS_TLAST => S_AXIS0_TLAST, + S_AXIS_TDEST => S_AXIS0_TDEST, + S_AXIS_TID => S_AXIS0_TID, + S_AXIS_TUSER => S_AXIS0_TUSER, + S_AXIS_TREADY => S_AXIS0_TREADY, + -- SURF AXI Stream Interface + axisClk => axisClk, + axisRst => axisRst, + axisMaster => sAxisMasters(0), + axisSlave => sAxisSlaves(0)); + + U_ShimLayerSlave_1 : entity surf.SlaveAxiStreamIpIntegrator + generic map ( + INTERFACENAME => "S_AXIS", + HAS_TLAST => 1, + HAS_TKEEP => 1, + HAS_TSTRB => 1, + HAS_TREADY => 1, + TUSER_WIDTH => TUSER_WIDTH_G, + TID_WIDTH => TID_WIDTH_G, + TDEST_WIDTH => TDEST_WIDTH_G, + TDATA_NUM_BYTES => TDATA_NUM_BYTES_G) + port map ( + -- IP Integrator AXI Stream Interface + S_AXIS_ACLK => AXIS_ACLK, + S_AXIS_ARESETN => AXIS_ARESETN, + S_AXIS_TVALID => S_AXIS1_TVALID, + S_AXIS_TDATA => S_AXIS1_TDATA, + S_AXIS_TSTRB => S_AXIS1_TSTRB, + S_AXIS_TKEEP => S_AXIS1_TKEEP, + S_AXIS_TLAST => S_AXIS1_TLAST, + S_AXIS_TDEST => S_AXIS1_TDEST, + S_AXIS_TID => S_AXIS1_TID, + S_AXIS_TUSER => S_AXIS1_TUSER, + S_AXIS_TREADY => S_AXIS1_TREADY, + -- SURF AXI Stream Interface + axisClk => open, + axisRst => open, + axisMaster => sAxisMasters(1), + axisSlave => sAxisSlaves(1)); + + U_ShimLayerMaster_0 : entity surf.MasterAxiStreamIpIntegrator + generic map ( + INTERFACENAME => "M_AXIS", + HAS_TLAST => 1, + HAS_TKEEP => 1, + HAS_TSTRB => 1, + HAS_TREADY => 1, + TUSER_WIDTH => TUSER_WIDTH_G, + TID_WIDTH => TID_WIDTH_G, + TDEST_WIDTH => TDEST_WIDTH_G, + TDATA_NUM_BYTES => TDATA_NUM_BYTES_G) + port map ( + -- IP Integrator AXI Stream Interface + M_AXIS_ACLK => AXIS_ACLK, + M_AXIS_ARESETN => AXIS_ARESETN, + M_AXIS_TVALID => M_AXIS0_TVALID, + M_AXIS_TDATA => M_AXIS0_TDATA, + M_AXIS_TSTRB => M_AXIS0_TSTRB, + M_AXIS_TKEEP => M_AXIS0_TKEEP, + M_AXIS_TLAST => M_AXIS0_TLAST, + M_AXIS_TDEST => M_AXIS0_TDEST, + M_AXIS_TID => M_AXIS0_TID, + M_AXIS_TUSER => M_AXIS0_TUSER, + M_AXIS_TREADY => M_AXIS0_TREADY, + -- SURF AXI Stream Interface + axisClk => open, + axisRst => open, + axisMaster => mAxisMasters(0), + axisSlave => mAxisSlaves(0)); + + U_ShimLayerMaster_1 : entity surf.MasterAxiStreamIpIntegrator + generic map ( + INTERFACENAME => "M_AXIS", + HAS_TLAST => 1, + HAS_TKEEP => 1, + HAS_TSTRB => 1, + HAS_TREADY => 1, + TUSER_WIDTH => TUSER_WIDTH_G, + TID_WIDTH => TID_WIDTH_G, + TDEST_WIDTH => TDEST_WIDTH_G, + TDATA_NUM_BYTES => TDATA_NUM_BYTES_G) + port map ( + -- IP Integrator AXI Stream Interface + M_AXIS_ACLK => AXIS_ACLK, + M_AXIS_ARESETN => AXIS_ARESETN, + M_AXIS_TVALID => M_AXIS1_TVALID, + M_AXIS_TDATA => M_AXIS1_TDATA, + M_AXIS_TSTRB => M_AXIS1_TSTRB, + M_AXIS_TKEEP => M_AXIS1_TKEEP, + M_AXIS_TLAST => M_AXIS1_TLAST, + M_AXIS_TDEST => M_AXIS1_TDEST, + M_AXIS_TID => M_AXIS1_TID, + M_AXIS_TUSER => M_AXIS1_TUSER, + M_AXIS_TREADY => M_AXIS1_TREADY, + -- SURF AXI Stream Interface + axisClk => open, + axisRst => open, + axisMaster => mAxisMasters(1), + axisSlave => mAxisSlaves(1)); + + U_ShimLayer : entity surf.SlaveAxiLiteIpIntegrator + generic map ( + EN_ERROR_RESP => true, + FREQ_HZ => 100000000, + ADDR_WIDTH => 32) + port map ( + -- IP Integrator AXI-Lite Interface + S_AXI_ACLK => AXIS_ACLK, + S_AXI_ARESETN => AXIS_ARESETN, + S_AXI_AWADDR => S_AXIL_AWADDR, + S_AXI_AWPROT => S_AXIL_AWPROT, + S_AXI_AWVALID => S_AXIL_AWVALID, + S_AXI_AWREADY => S_AXIL_AWREADY, + S_AXI_WDATA => S_AXIL_WDATA, + S_AXI_WSTRB => S_AXIL_WSTRB, + S_AXI_WVALID => S_AXIL_WVALID, + S_AXI_WREADY => S_AXIL_WREADY, + S_AXI_BRESP => S_AXIL_BRESP, + S_AXI_BVALID => S_AXIL_BVALID, + S_AXI_BREADY => S_AXIL_BREADY, + S_AXI_ARADDR => S_AXIL_ARADDR, + S_AXI_ARPROT => S_AXIL_ARPROT, + S_AXI_ARVALID => S_AXIL_ARVALID, + S_AXI_ARREADY => S_AXIL_ARREADY, + S_AXI_RDATA => S_AXIL_RDATA, + S_AXI_RRESP => S_AXIL_RRESP, + S_AXI_RVALID => S_AXIL_RVALID, + S_AXI_RREADY => S_AXIL_RREADY, + -- SURF AXI-Lite Interface + axilClk => open, + axilRst => open, + axilReadMaster => axilReadMaster, + axilReadSlave => axilReadSlave, + axilWriteMaster => axilWriteMaster, + axilWriteSlave => axilWriteSlave); + + U_AXIL_XBAR : entity surf.AxiLiteCrossbar + generic map ( + TPD_G => TPD_C, + NUM_SLAVE_SLOTS_G => 1, + NUM_MASTER_SLOTS_G => 2, + MASTERS_CONFIG_G => AXIL_CONFIG_C) + port map ( + axiClk => axisClk, + axiClkRst => axisRst, + sAxiWriteMasters(0) => axilWriteMaster, + sAxiWriteSlaves(0) => axilWriteSlave, + sAxiReadMasters(0) => axilReadMaster, + sAxiReadSlaves(0) => axilReadSlave, + mAxiWriteMasters => axilWriteMasters, + mAxiWriteSlaves => axilWriteSlaves, + mAxiReadMasters => axilReadMasters, + mAxiReadSlaves => axilReadSlaves); + + --------------------------------------------------------------------------- + -- Design Under Testing (DUT) Modules + --------------------------------------------------------------------------- + + -- Module used on the front end board for sequencing the frames to back end + U_DUT_MUX : entity surf.EventFrameSequencerMux + generic map ( + TPD_G => TPD_C, + NUM_SLAVES_G => 2, + MODE_G => "ROUTED", + TDEST_ROUTES_G => ( + 0 => "0000000-", -- Trig on 0x1, Event on 0x0 + 1 => "00000010"), -- Map PGP[tap] to TDEST 0x2 + TRANS_TDEST_G => X"00", + AXIS_CONFIG_G => AXIS_CONFIG_C) + port map ( + -- Clock and Reset + axisClk => axisClk, + axisRst => axisRst, + -- AXI-Lite Interface (axisClk domain) + axilReadMaster => axilReadMasters(0), + axilReadSlave => axilReadSlaves(0), + axilWriteMaster => axilWriteMasters(0), + axilWriteSlave => axilWriteSlaves(0), + -- AXIS Interfaces + sAxisMasters => sAxisMasters, + sAxisSlaves => sAxisSlaves, + mAxisMaster => axisMaster, + mAxisSlave => axisSlave); + + -- Module used on the back end board (e.g. FPGA PCIe) for decoding + U_DUT_DEMUX : entity surf.EventFrameSequencerDemux + generic map ( + TPD_G => TPD_C, + NUM_MASTERS_G => 2, + AXIS_CONFIG_G => AXIS_CONFIG_C) + port map ( + -- Clock and Reset + axisClk => axisClk, + axisRst => axisRst, + -- AXI-Lite Interface + axilReadMaster => axilReadMasters(1), + axilReadSlave => axilReadSlaves(1), + axilWriteMaster => axilWriteMasters(1), + axilWriteSlave => axilWriteSlaves(1), + -- AXIS Interfaces + sAxisMaster => axisMaster, + sAxisSlave => axisSlave, + mAxisMasters => mAxisMasters, + mAxisSlaves => mAxisSlaves); + +end mapping; diff --git a/tests/test_EventFrameSequencerTb.py b/tests/test_EventFrameSequencerTb.py new file mode 100755 index 0000000000..5add8bee48 --- /dev/null +++ b/tests/test_EventFrameSequencerTb.py @@ -0,0 +1,199 @@ +############################################################################## +## This file is part of 'SLAC Firmware Standard Library'. +## It is subject to the license terms in the LICENSE.txt file found in the +## top-level directory of this distribution and at: +## https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +## No part of 'SLAC Firmware Standard Library', including this file, +## may be copied, modified, propagated, or distributed except according to +## the terms contained in the LICENSE.txt file. +############################################################################## + +# dut_tb +import itertools +import logging +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge +from cocotb.regression import TestFactory + +from cocotbext.axi import AxiStreamFrame, AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiLiteBus, AxiLiteMaster + +# test_EventFrameSequencerTb +from cocotb_test.simulator import run +import pytest +import glob +import os + +# Define a new log level +CUSTOM_LEVEL = 60 +logging.addLevelName(CUSTOM_LEVEL, "CUSTOM") + +def custom(self, message, *args, **kwargs): + if self.isEnabledFor(CUSTOM_LEVEL): + self._log(CUSTOM_LEVEL, message, args, **kwargs) + +# Add the custom level to the logging.Logger class +logging.Logger.custom = custom + +class TB: + def __init__(self, dut): + + # Pointer to DUT object + self.dut = dut + + self.log = logging.getLogger('cocotb.tb') + self.log.setLevel(logging.DEBUG) + + # Start AXIS_ACLK clock (100 MHz) in a separate thread + cocotb.start_soon(Clock(dut.AXIS_ACLK, 10.0, units='ns').start()) + + # Setup the AXI stream source + self.sources = [None for _ in range(2)] + for i in range(2): + self.sources[i] = AxiStreamSource( + bus = AxiStreamBus.from_prefix(dut, f'S_AXIS{i}'), + clock = dut.AXIS_ACLK, + reset = dut.AXIS_ARESETN, + reset_active_level = False, + ) + + # Setup the AXI stream sink + self.sinks = [None for _ in range(2)] + for i in range(2): + self.sinks[i] = AxiStreamSink( + bus = AxiStreamBus.from_prefix(dut, f'M_AXIS{i}'), + clock = dut.AXIS_ACLK, + reset = dut.AXIS_ARESETN, + reset_active_level = False, + ) + + # Create the AXI-Lite Master + self.axil_master = AxiLiteMaster( + bus = AxiLiteBus.from_prefix(dut, 'S_AXIL'), + clock = dut.AXIS_ACLK, + reset = dut.AXIS_ARESETN, + reset_active_level=False) + + async def cycle_reset(self): + self.dut.AXIS_ARESETN.setimmediatevalue(0) + await RisingEdge(self.dut.AXIS_ACLK) + await RisingEdge(self.dut.AXIS_ACLK) + self.dut.AXIS_ARESETN.value = 0 + await RisingEdge(self.dut.AXIS_ACLK) + await RisingEdge(self.dut.AXIS_ACLK) + self.dut.AXIS_ARESETN.value = 1 + await RisingEdge(self.dut.AXIS_ACLK) + await RisingEdge(self.dut.AXIS_ACLK) + +async def run_test(dut): + + tb = TB(dut) + await tb.cycle_reset() + + # Byte sweeping to check for corner cases + for x in range(8): + + # Generate the transition data frame + trans_frame = AxiStreamFrame(bytearray(list(range(0+x, 16)))) + trans_frame.tdest = 0x0 + trans_frame.tuser = x + + # Generate the payload data frames + test_frames = [None for _ in range(2)] + for i in range(2): + test_frames[i] = AxiStreamFrame(bytearray(list(range(1+i+x, 16+1)))) + test_frames[i].tdest = i+1 + test_frames[i].tuser = x + + # Send the transition frame + await tb.sources[0].send(trans_frame) + tb.log.custom( f'trans_frame.tdata={trans_frame.tdata}' ) + tb.log.custom( f'trans_frame.tdest={trans_frame.tdest}' ) + tb.log.custom( f'trans_frame.tuser={trans_frame.tuser}' ) + + # Received the transition frame + rx_frame = await tb.sinks[0].recv() + tb.log.custom( f'rx_frame.tdata={rx_frame.tdata}' ) + tb.log.custom( f'rx_frame.tdest={rx_frame.tdest}' ) + tb.log.custom( f'rx_frame.tuser={rx_frame.tuser}' ) + assert rx_frame.tdata == trans_frame.tdata + assert rx_frame.tdest == trans_frame.tdest + assert rx_frame.tuser == trans_frame.tuser + assert tb.sinks[0].empty() + + # Send the payload data frames + for i in range(2): + tb.log.custom( f'test_frames[{i}].tdata={test_frames[i].tdata}' ) + tb.log.custom( f'test_frames[{i}].tdest={test_frames[i].tdest}' ) + tb.log.custom( f'test_frames[{i}].tuser={test_frames[i].tuser}' ) + await tb.sources[i].send(test_frames[i]) + + # Received the payload data frame + for i in range(2): + rx_frame = await tb.sinks[i].recv() + tb.log.custom( f'rx_frame.tdata={rx_frame.tdata}' ) + tb.log.custom( f'rx_frame.tdest={rx_frame.tdest}' ) + tb.log.custom( f'rx_frame.tuser={rx_frame.tuser}' ) + assert rx_frame.tdata == test_frames[i].tdata + assert rx_frame.tdest == test_frames[i].tdest + assert rx_frame.tuser == test_frames[i].tuser + assert tb.sinks[i].empty() + +if cocotb.SIM_NAME: + factory = TestFactory(run_test) + factory.generate_tests() + +tests_dir = os.path.dirname(__file__) +tests_module = 'EventFrameSequencerTb' + +############################################################################## + +@pytest.mark.parametrize( + "parameters", [ + None + ]) +def test_EventFrameSequencerTb(parameters): + + # https://github.com/themperek/cocotb-test#arguments-for-simulatorrun + # https://github.com/themperek/cocotb-test/blob/master/cocotb_test/simulator.py + run( + # top level HDL + toplevel = f'surf.{tests_module}'.lower(), + + # name of the file that contains @cocotb.test() -- this file + # https://docs.cocotb.org/en/stable/building.html?#envvar-MODULE + module = f'test_{tests_module}', + + # https://docs.cocotb.org/en/stable/building.html?#var-TOPLEVEL_LANG + toplevel_lang = 'vhdl', + + # VHDL source files to include. + # Can be specified as a list or as a dict of lists with the library name as key, + # if the simulator supports named libraries. + vhdl_sources = { + 'surf' : glob.glob(f'{tests_dir}/../build/SRC_VHDL/surf/*'), + 'ruckus' : glob.glob(f'{tests_dir}/../build/SRC_VHDL/ruckus/*'), + }, + + # A dictionary of top-level parameters/generics. + parameters = parameters, + + # The directory used to compile the tests. (default: sim_build) + sim_build = f'{tests_dir}/sim_build/{tests_module}', + + # A dictionary of extra environment variables set in simulator process. + extra_env=parameters, + + # Select a simulator + simulator="ghdl", + + # use of synopsys package "std_logic_arith" needs the -fsynopsys option + # -frelaxed-rules option to allow IP integrator attributes + # When two operators are overloaded, give preference to the explicit declaration (-fexplicit) + vhdl_compile_args = ['-fsynopsys','-frelaxed-rules', '-fexplicit'], + + ######################################################################## + # Dump waveform to file ($ gtkwave sim_build/path/To/{tests_module}.ghw) + ######################################################################## + sim_args =[f'--wave={tests_module}.ghw'], + )