diff --git a/axi/axi-lite/rtl/AxiDualPortRam.vhd b/axi/axi-lite/rtl/AxiDualPortRam.vhd index 6e50266ca0..60047b36d8 100644 --- a/axi/axi-lite/rtl/AxiDualPortRam.vhd +++ b/axi/axi-lite/rtl/AxiDualPortRam.vhd @@ -361,11 +361,11 @@ begin if (AXI_WR_EN_G) then v.axiAddr := axiWriteMaster.awaddr(AXI_RAM_ADDR_HIGH_C downto AXI_RAM_ADDR_LOW_C); if (DATA_WIDTH_G <= 32) then - decAddrInt := conv_integer(axiWriteMaster.awaddr(AXI_RAM_ADDR_LOW_C-1 downto 0)); + v.axiWrStrobe := axiWriteMaster.wstrb; else decAddrInt := conv_integer(axiWriteMaster.awaddr(AXI_DEC_ADDR_RANGE_C)); + v.axiWrStrobe((decAddrInt+1)*4-1 downto decAddrInt*4) := axiWriteMaster.wstrb; end if; - v.axiWrStrobe((decAddrInt+1)*4-1 downto decAddrInt*4) := axiWriteMaster.wstrb; end if; axiSlaveWriteResponse(v.axiWriteSlave, ite(AXI_WR_EN_G, AXI_RESP_OK_C, AXI_RESP_SLVERR_C)); -- Check for read transaction diff --git a/axi/axi-lite/tb/AxiLiteCrossbarTb.vhd b/axi/axi-lite/tb/AxiLiteCrossbarTb.vhd new file mode 100644 index 0000000000..f897644063 --- /dev/null +++ b/axi/axi-lite/tb/AxiLiteCrossbarTb.vhd @@ -0,0 +1,189 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: surf.AxiLiteCrossbar 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; + +entity AxiLiteCrossbarTb is + port ( + -- AXI-Lite Interface + S_AXI_ACLK : in std_logic; + S_AXI_ARESETN : in std_logic; + S_AXI_AWADDR : in std_logic_vector(31 downto 0); + S_AXI_AWPROT : in std_logic_vector(2 downto 0); + S_AXI_AWVALID : in std_logic; + S_AXI_AWREADY : out std_logic; + S_AXI_WDATA : in std_logic_vector(31 downto 0); + S_AXI_WSTRB : in std_logic_vector(3 downto 0); + S_AXI_WVALID : in std_logic; + S_AXI_WREADY : out std_logic; + S_AXI_BRESP : out std_logic_vector(1 downto 0); + S_AXI_BVALID : out std_logic; + S_AXI_BREADY : in std_logic; + S_AXI_ARADDR : in std_logic_vector(31 downto 0); + S_AXI_ARPROT : in std_logic_vector(2 downto 0); + S_AXI_ARVALID : in std_logic; + S_AXI_ARREADY : out std_logic; + S_AXI_RDATA : out std_logic_vector(31 downto 0); + S_AXI_RRESP : out std_logic_vector(1 downto 0); + S_AXI_RVALID : out std_logic; + S_AXI_RREADY : in std_logic); +end AxiLiteCrossbarTb; + +architecture mapping of AxiLiteCrossbarTb is + + constant NUM_AXIL_MASTERS_C : positive := 2; + + constant AXIL_XBAR_CONFIG_C : AxiLiteCrossbarMasterConfigArray(NUM_AXIL_MASTERS_C-1 downto 0) := genAxiLiteConfig(NUM_AXIL_MASTERS_C, x"0000_0000", 22, 20); + + constant NUM_CASCADE_MASTERS_C : positive := 2; + + constant CASCADE_XBAR_CONFIG_C : AxiLiteCrossbarMasterConfigArray(NUM_CASCADE_MASTERS_C-1 downto 0) := ( + 0 => ( + baseAddr => x"0010_2000", + addrBits => 12, + connectivity => X"0001"), + 1 => ( + baseAddr => x"0016_0000", + addrBits => 17, + connectivity => X"0001")); + + signal axilClk : sl; + signal axilRst : sl; + + signal axilReadMaster : AxiLiteReadMasterType; + signal axilReadSlave : AxiLiteReadSlaveType; + signal axilWriteMaster : AxiLiteWriteMasterType; + signal axilWriteSlave : AxiLiteWriteSlaveType; + + signal axilReadMasters : AxiLiteReadMasterArray(NUM_AXIL_MASTERS_C-1 downto 0); + signal axilReadSlaves : AxiLiteReadSlaveArray(NUM_AXIL_MASTERS_C-1 downto 0) := (others => AXI_LITE_READ_SLAVE_EMPTY_DECERR_C); + signal axilWriteMasters : AxiLiteWriteMasterArray(NUM_AXIL_MASTERS_C-1 downto 0); + signal axilWriteSlaves : AxiLiteWriteSlaveArray(NUM_AXIL_MASTERS_C-1 downto 0) := (others => AXI_LITE_WRITE_SLAVE_EMPTY_DECERR_C); + + signal cascadeReadMasters : AxiLiteReadMasterArray(NUM_CASCADE_MASTERS_C-1 downto 0); + signal cascadeReadSlaves : AxiLiteReadSlaveArray(NUM_CASCADE_MASTERS_C-1 downto 0) := (others => AXI_LITE_READ_SLAVE_EMPTY_DECERR_C); + signal cascadeWriteMasters : AxiLiteWriteMasterArray(NUM_CASCADE_MASTERS_C-1 downto 0); + signal cascadeWriteSlaves : AxiLiteWriteSlaveArray(NUM_CASCADE_MASTERS_C-1 downto 0) := (others => AXI_LITE_WRITE_SLAVE_EMPTY_DECERR_C); + +begin + + U_ShimLayer : entity surf.SlaveAxiLiteIpIntegrator + generic map ( + EN_ERROR_RESP => true, + FREQ_HZ => 125000000, + ADDR_WIDTH => 32) + port map ( + -- IP Integrator AXI-Lite Interface + S_AXI_ACLK => S_AXI_ACLK, + S_AXI_ARESETN => S_AXI_ARESETN, + S_AXI_AWADDR => S_AXI_AWADDR, + S_AXI_AWPROT => S_AXI_AWPROT, + S_AXI_AWVALID => S_AXI_AWVALID, + S_AXI_AWREADY => S_AXI_AWREADY, + S_AXI_WDATA => S_AXI_WDATA, + S_AXI_WSTRB => S_AXI_WSTRB, + S_AXI_WVALID => S_AXI_WVALID, + S_AXI_WREADY => S_AXI_WREADY, + S_AXI_BRESP => S_AXI_BRESP, + S_AXI_BVALID => S_AXI_BVALID, + S_AXI_BREADY => S_AXI_BREADY, + S_AXI_ARADDR => S_AXI_ARADDR, + S_AXI_ARPROT => S_AXI_ARPROT, + S_AXI_ARVALID => S_AXI_ARVALID, + S_AXI_ARREADY => S_AXI_ARREADY, + S_AXI_RDATA => S_AXI_RDATA, + S_AXI_RRESP => S_AXI_RRESP, + S_AXI_RVALID => S_AXI_RVALID, + S_AXI_RREADY => S_AXI_RREADY, + -- SURF AXI-Lite Interface + axilClk => axilClk, + axilRst => axilRst, + axilReadMaster => axilReadMaster, + axilReadSlave => axilReadSlave, + axilWriteMaster => axilWriteMaster, + axilWriteSlave => axilWriteSlave); + + U_AXIL_XBAR : entity surf.AxiLiteCrossbar + generic map ( + NUM_SLAVE_SLOTS_G => 1, + NUM_MASTER_SLOTS_G => NUM_AXIL_MASTERS_C, + MASTERS_CONFIG_G => AXIL_XBAR_CONFIG_C) + port map ( + axiClk => axilClk, + axiClkRst => axilRst, + sAxiWriteMasters(0) => axilWriteMaster, + sAxiWriteSlaves(0) => axilWriteSlave, + sAxiReadMasters(0) => axilReadMaster, + sAxiReadSlaves(0) => axilReadSlave, + mAxiWriteMasters => axilWriteMasters, + mAxiWriteSlaves => axilWriteSlaves, + mAxiReadMasters => axilReadMasters, + mAxiReadSlaves => axilReadSlaves); + + U_MEM : entity surf.AxiDualPortRam + generic map ( + ADDR_WIDTH_G => 10, + DATA_WIDTH_G => 32) + port map ( + -- Axi Port + axiClk => axilClk, + axiRst => axilRst, + axiReadMaster => axilReadMasters(0), + axiReadSlave => axilReadSlaves(0), + axiWriteMaster => axilWriteMasters(0), + axiWriteSlave => axilWriteSlaves(0)); + + U_CASCADE_XBAR : entity surf.AxiLiteCrossbar + generic map ( + NUM_SLAVE_SLOTS_G => 1, + NUM_MASTER_SLOTS_G => NUM_CASCADE_MASTERS_C, + MASTERS_CONFIG_G => CASCADE_XBAR_CONFIG_C) + port map ( + axiClk => axilClk, + axiClkRst => axilRst, + sAxiWriteMasters(0) => axilWriteMasters(1), + sAxiWriteSlaves(0) => axilWriteSlaves(1), + sAxiReadMasters(0) => axilReadMasters(1), + sAxiReadSlaves(0) => axilReadSlaves(1), + mAxiWriteMasters => cascadeWriteMasters, + mAxiWriteSlaves => cascadeWriteSlaves, + mAxiReadMasters => cascadeReadMasters, + mAxiReadSlaves => cascadeReadSlaves); + + GEN_VEC : + for i in NUM_CASCADE_MASTERS_C-1 downto 0 generate + + U_MEM : entity surf.AxiDualPortRam + generic map ( + ADDR_WIDTH_G => 10, + DATA_WIDTH_G => 32) + port map ( + -- Axi Port + axiClk => axilClk, + axiRst => axilRst, + axiReadMaster => cascadeReadMasters(i), + axiReadSlave => cascadeReadSlaves(i), + axiWriteMaster => cascadeWriteMasters(i), + axiWriteSlave => cascadeWriteSlaves(i)); + + end generate GEN_VEC; + +end mapping; diff --git a/axi/axi-stream/tb/AxiStreamDemuxMuxTb.vhd b/axi/axi-stream/tb/AxiStreamDemuxMuxTb.vhd new file mode 100644 index 0000000000..330106d80e --- /dev/null +++ b/axi/axi-stream/tb/AxiStreamDemuxMuxTb.vhd @@ -0,0 +1,175 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: surf.AxiStreamDemux/surf.AxiStreamMux 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.AxiStreamPkg.all; + +entity AxiStreamDemuxMuxTb is + generic ( + -- AXI Stream Configuration + TUSER_WIDTH_G : positive range 1 to 8 := 1; + TID_WIDTH_G : positive range 1 to 8 := 1; + TDEST_WIDTH_G : positive range 1 to 8 := 1; + TDATA_NUM_BYTES_G : positive range 1 to 128 := 1; + MUX_STREAMS_G : positive := 2; + PIPE_STAGES_G : natural := 0; + ILEAVE_EN_G : boolean := false; + ILEAVE_ON_NOTVALID_G : boolean := false; + ILEAVE_REARB_G : natural := 0; + REARB_DELAY_G : boolean := true; + FORCED_REARB_HOLD_G : boolean := false); + port ( + -- Clock and Reset + AXIS_ACLK : in std_logic := '0'; + AXIS_ARESETN : in std_logic := '0'; + -- IP Integrator Slave AXI Stream Interface + S_AXIS_TVALID : in std_logic := '0'; + S_AXIS_TDATA : in std_logic_vector((8*TDATA_NUM_BYTES_G)-1 downto 0) := (others => '0'); + S_AXIS_TSTRB : in std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0) := (others => '0'); + S_AXIS_TKEEP : in std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0) := (others => '0'); + S_AXIS_TLAST : in std_logic := '0'; + S_AXIS_TDEST : in std_logic_vector(TDEST_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS_TID : in std_logic_vector(TID_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS_TUSER : in std_logic_vector(TUSER_WIDTH_G-1 downto 0) := (others => '0'); + S_AXIS_TREADY : out std_logic; + -- IP Integrator Master AXI Stream Interface + M_AXIS_TVALID : out std_logic; + M_AXIS_TDATA : out std_logic_vector((8*TDATA_NUM_BYTES_G)-1 downto 0); + M_AXIS_TSTRB : out std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0); + M_AXIS_TKEEP : out std_logic_vector(TDATA_NUM_BYTES_G-1 downto 0); + M_AXIS_TLAST : out std_logic; + M_AXIS_TDEST : out std_logic_vector(TDEST_WIDTH_G-1 downto 0); + M_AXIS_TID : out std_logic_vector(TID_WIDTH_G-1 downto 0); + M_AXIS_TUSER : out std_logic_vector(TUSER_WIDTH_G-1 downto 0); + M_AXIS_TREADY : in std_logic); +end AxiStreamDemuxMuxTb; + +architecture mapping of AxiStreamDemuxMuxTb is + + signal axisClk : sl := '0'; + signal axisRst : sl := '0'; + + signal sAxisMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal sAxisSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + + signal axisMasters : AxiStreamMasterArray(MUX_STREAMS_G-1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal axisSlaves : AxiStreamSlaveArray(MUX_STREAMS_G-1 downto 0) := (others => AXI_STREAM_SLAVE_FORCE_C); + + signal mAxisMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal mAxisSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_FORCE_C; + +begin + + U_ShimLayerSlave : 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_AXIS_TVALID, + S_AXIS_TDATA => S_AXIS_TDATA, + S_AXIS_TSTRB => S_AXIS_TSTRB, + S_AXIS_TKEEP => S_AXIS_TKEEP, + S_AXIS_TLAST => S_AXIS_TLAST, + S_AXIS_TDEST => S_AXIS_TDEST, + S_AXIS_TID => S_AXIS_TID, + S_AXIS_TUSER => S_AXIS_TUSER, + S_AXIS_TREADY => S_AXIS_TREADY, + -- SURF AXI Stream Interface + axisClk => axisClk, + axisRst => axisRst, + axisMaster => sAxisMaster, + axisSlave => sAxisSlave); + + U_DeMux : entity surf.AxiStreamDeMux + generic map ( + NUM_MASTERS_G => MUX_STREAMS_G, + PIPE_STAGES_G => PIPE_STAGES_G) + port map ( + -- Clock and reset + axisClk => axisClk, + axisRst => axisRst, + -- Slave + sAxisMaster => sAxisMaster, + sAxisSlave => sAxisSlave, + -- Masters + mAxisMasters => axisMasters, + mAxisSlaves => axisSlaves); + + U_Mux : entity surf.AxiStreamMux + generic map ( + NUM_SLAVES_G => MUX_STREAMS_G, + PIPE_STAGES_G => PIPE_STAGES_G, + ILEAVE_EN_G => ILEAVE_EN_G, + ILEAVE_ON_NOTVALID_G => ILEAVE_ON_NOTVALID_G, + ILEAVE_REARB_G => ILEAVE_REARB_G, + REARB_DELAY_G => REARB_DELAY_G, + FORCED_REARB_HOLD_G => FORCED_REARB_HOLD_G) + port map ( + -- Clock and reset + axisClk => axisClk, + axisRst => axisRst, + -- Slaves + sAxisMasters => axisMasters, + sAxisSlaves => axisSlaves, + -- Master + mAxisMaster => mAxisMaster, + mAxisSlave => mAxisSlave); + + U_ShimLayerMaster : 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_AXIS_TVALID, + M_AXIS_TDATA => M_AXIS_TDATA, + M_AXIS_TSTRB => M_AXIS_TSTRB, + M_AXIS_TKEEP => M_AXIS_TKEEP, + M_AXIS_TLAST => M_AXIS_TLAST, + M_AXIS_TDEST => M_AXIS_TDEST, + M_AXIS_TID => M_AXIS_TID, + M_AXIS_TUSER => M_AXIS_TUSER, + M_AXIS_TREADY => M_AXIS_TREADY, + -- SURF AXI Stream Interface + axisClk => open, + axisRst => open, + axisMaster => mAxisMaster, + axisSlave => mAxisSlave); + +end mapping; diff --git a/tests/test_AxiLiteCrossbarTb.py b/tests/test_AxiLiteCrossbarTb.py new file mode 100644 index 0000000000..03d9a5e950 --- /dev/null +++ b/tests/test_AxiLiteCrossbarTb.py @@ -0,0 +1,264 @@ +############################################################################## +## 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. +############################################################################## + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Timer +from cocotb.regression import TestFactory + +from cocotbext.axi import AxiLiteBus, AxiLiteMaster + +# test_AxiLiteCrossbarTb +from cocotb_test.simulator import run +import pytest +import glob +import os +import itertools +import logging +import random + +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 clock (125 MHz) in a separate thread + cocotb.start_soon(Clock(dut.S_AXI_ACLK, 8.0, units='ns').start()) + + # Create the AXI-Lite Master + self.axil_master = AxiLiteMaster( + bus = AxiLiteBus.from_prefix(dut, 'S_AXI'), + clock = dut.S_AXI_ACLK, + reset = dut.S_AXI_ARESETN, + reset_active_level=False) + + def set_idle_generator(self, generator=None): + if generator: + self.axil_master.write_if.aw_channel.set_pause_generator(generator()) + self.axil_master.write_if.w_channel.set_pause_generator(generator()) + self.axil_master.read_if.ar_channel.set_pause_generator(generator()) + + def set_backpressure_generator(self, generator=None): + if generator: + self.axil_master.write_if.b_channel.set_pause_generator(generator()) + self.axil_master.read_if.r_channel.set_pause_generator(generator()) + + async def cycle_reset(self): + self.dut.S_AXI_ARESETN.setimmediatevalue(0) + await RisingEdge(self.dut.S_AXI_ACLK) + await RisingEdge(self.dut.S_AXI_ACLK) + self.dut.S_AXI_ARESETN.value = 0 + await RisingEdge(self.dut.S_AXI_ACLK) + await RisingEdge(self.dut.S_AXI_ACLK) + self.dut.S_AXI_ARESETN.value = 1 + await RisingEdge(self.dut.S_AXI_ACLK) + await RisingEdge(self.dut.S_AXI_ACLK) + +async def run_test_bytes(dut, data_in=None, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.axil_master.write_if.byte_lanes + + await tb.cycle_reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + for length in range(1, byte_lanes*2): + for memDev in [0x0000_0000,0x0010_2000,0x0016_0000]: + for offset in range(byte_lanes): + addr = offset+memDev + tb.log.info( f'length={length},addr={hex(addr)}' ) + test_data = bytearray([x % 256 for x in range(length)]) + await tb.axil_master.write(addr, test_data) + data = await tb.axil_master.read(addr, length) + assert data.data == test_data + + await RisingEdge(dut.S_AXI_ACLK) + await RisingEdge(dut.S_AXI_ACLK) + + +async def run_test_words(dut): + + tb = TB(dut) + + byte_lanes = tb.axil_master.write_if.byte_lanes + + await tb.cycle_reset() + + for length in list(range(1, 4)): + for memDev in [0x0000_0000,0x0010_2000,0x0016_0000]: + for offset in list(range(byte_lanes)): + addr = offset + tb.log.info( f'length={length},addr={hex(addr)}' ) + + test_data = bytearray([x % 256 for x in range(length)]) + event = tb.axil_master.init_write(addr, test_data) + await event.wait() + event = tb.axil_master.init_read(addr, length) + await event.wait() + assert event.data.data == test_data + + test_data = bytearray([x % 256 for x in range(length)]) + await tb.axil_master.write(addr, test_data) + assert (await tb.axil_master.read(addr, length)).data == test_data + + test_data = [x * 0x1001 for x in range(length)] + await tb.axil_master.write_words(addr, test_data) + assert await tb.axil_master.read_words(addr, length) == test_data + + test_data = [x * 0x10200201 for x in range(length)] + await tb.axil_master.write_dwords(addr, test_data) + assert await tb.axil_master.read_dwords(addr, length) == test_data + + test_data = [x * 0x1020304004030201 for x in range(length)] + await tb.axil_master.write_qwords(addr, test_data) + assert await tb.axil_master.read_qwords(addr, length) == test_data + + test_data = 0x01*length + await tb.axil_master.write_byte(addr, test_data) + assert await tb.axil_master.read_byte(addr) == test_data + + test_data = 0x1001*length + await tb.axil_master.write_word(addr, test_data) + assert await tb.axil_master.read_word(addr) == test_data + + test_data = 0x10200201*length + await tb.axil_master.write_dword(addr, test_data) + assert await tb.axil_master.read_dword(addr) == test_data + + test_data = 0x1020304004030201*length + await tb.axil_master.write_qword(addr, test_data) + assert await tb.axil_master.read_qword(addr) == test_data + + await RisingEdge(dut.S_AXI_ACLK) + await RisingEdge(dut.S_AXI_ACLK) + +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + await tb.cycle_reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + async def worker(master, offset, aperture, count=16): + for k in range(count): + length = random.randint(1, min(32, aperture)) + addr = offset+random.randint(0, aperture-length) + test_data = bytearray([x % 256 for x in range(length)]) + + await Timer(random.randint(1, 100), 'ns') + + await master.write(addr, test_data) + + await Timer(random.randint(1, 100), 'ns') + + data = await master.read(addr, length) + assert data.data == test_data + + workers = [] + + for k in [0x0000_0000,0x0010_2000,0x0016_0000]: + workers.append(cocotb.start_soon(worker(tb.axil_master, k, 0x1000, count=16))) + + while workers: + await workers.pop(0).join() + + await RisingEdge(dut.S_AXI_ACLK) + await RisingEdge(dut.S_AXI_ACLK) + + +def cycle_pause(): + return itertools.cycle([1, 1, 1, 0]) + + +if cocotb.SIM_NAME: + + ################# + # run_test_bytes + ################# + factory = TestFactory(run_test_bytes) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + + ################# + # run_test_words + ################# + factory = TestFactory(run_test_words) + factory.generate_tests() + + ################# + # run_stress_test + ################# + factory = TestFactory(run_stress_test) + factory.generate_tests() + +tests_dir = os.path.dirname(__file__) +tests_module = 'AxiLiteCrossbarTb' + +############################################################################## + +@pytest.mark.parametrize( + "parameters", [ + None + ]) +def test_AxiLiteCrossbarTb(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'], + ) diff --git a/tests/test_AxiStreamDemuxMuxTb.py b/tests/test_AxiStreamDemuxMuxTb.py new file mode 100644 index 0000000000..4a31856021 --- /dev/null +++ b/tests/test_AxiStreamDemuxMuxTb.py @@ -0,0 +1,180 @@ +############################################################################## +## 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 + +# test_AxiStreamDemuxMuxTb +from cocotb_test.simulator import run +import pytest +import glob +import os + +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 (200 MHz) in a separate thread + cocotb.start_soon(Clock(dut.AXIS_ACLK, 5.0, units='ns').start()) + + # Setup the AXI stream source + self.source = AxiStreamSource( + bus = AxiStreamBus.from_prefix(dut, "S_AXIS"), + clock = dut.AXIS_ACLK, + reset = dut.AXIS_ARESETN, + reset_active_level = False, + ) + + # Setup the AXI stream sink + self.sink = AxiStreamSink( + bus = AxiStreamBus.from_prefix(dut, "M_AXIS"), + clock = dut.AXIS_ACLK, + reset = dut.AXIS_ARESETN, + reset_active_level = False, + ) + + def set_idle_generator(self, generator=None): + if generator: + self.source.set_pause_generator(generator()) + + def set_backpressure_generator(self, generator=None): + if generator: + self.sink.set_pause_generator(generator()) + + 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, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.cycle_reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for test_data in [payload_data(x) for x in payload_lengths()]: + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + await tb.source.send(test_frame) + + test_frames.append(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + +def cycle_pause(): + return itertools.cycle([1, 1, 1, 0]) + +def size_list(): + return list(range(1, 32+1)) + +def incrementing_payload(length): + return bytearray(itertools.islice(itertools.cycle(range(256)), length)) + +if cocotb.SIM_NAME: + factory = TestFactory(run_test) + factory.add_option("payload_lengths", [size_list]) + factory.add_option("payload_data", [incrementing_payload]) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + +tests_dir = os.path.dirname(__file__) +tests_module = 'AxiStreamDemuxMuxTb' + +############################################################################## + +@pytest.mark.parametrize( + "parameters", [ + {'MUX_STREAMS_G': '2', 'PIPE_STAGES_G': '0'}, + {'MUX_STREAMS_G': '3', 'PIPE_STAGES_G': '1'}, + ]) +def test_AxiStreamDemuxMuxTb(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}.' + ",".join((f"{key}={value}" for key, value in parameters.items())), + + # 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'], + ) diff --git a/tests/test_LineCode10b12bTb.py b/tests/test_LineCode10b12bTb.py index ed76db45ca..099cb906e3 100644 --- a/tests/test_LineCode10b12bTb.py +++ b/tests/test_LineCode10b12bTb.py @@ -157,7 +157,7 @@ def test_LineCode10b12bTb(parameters): parameters = parameters, # The directory used to compile the tests. (default: sim_build) - sim_build = f'{tests_dir}/sim_build/{tests_module}.', + sim_build = f'{tests_dir}/sim_build/{tests_module}', # A dictionary of extra environment variables set in simulator process. extra_env=parameters, diff --git a/tests/test_LineCode12b14bTb.py b/tests/test_LineCode12b14bTb.py index fdd4c0f817..f429e68937 100644 --- a/tests/test_LineCode12b14bTb.py +++ b/tests/test_LineCode12b14bTb.py @@ -221,7 +221,7 @@ def test_LineCode12b14bTb(parameters): parameters = parameters, # The directory used to compile the tests. (default: sim_build) - sim_build = f'{tests_dir}/sim_build/{tests_module}.', + sim_build = f'{tests_dir}/sim_build/{tests_module}', # A dictionary of extra environment variables set in simulator process. extra_env=parameters,