def nt_timestamp_test(dut): """Main test bench function. TODO: no automatic validation of DUT output yet. Look at waveforms. """ # start the clock cocotb.fork(clk_gen(dut.clk156, CLK_FREQ_MHZ)) # reset dut yield rstn(dut.clk156, dut.rstn156) # create axi lite writer, connect and reset axi_writer = AXI_Lite_Writer() axi_writer.connect(dut, dut.clk156, AXI_DATA_WIDTH, "ctrl") yield axi_writer.rst() # run simulation for a while yield wait_n_cycles(dut.clk156, 1000) # set number of clock cycles which shall pass until counter is incremented # to 10 yield axi_writer.write(CPUREG_OFFSET_CTRL_CYCLES_PER_TICK, 10) # run simulation for a while yield wait_n_cycles(dut.clk156, 1000)
def nt_recv_filter_mac_top_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # no software reset dut.rst_sw <= 0 # reset the dut yield rstn(dut.clk, dut.rstn) # create, connect and reset AXI4-Lite writer axi_lite_writer = AXI_Lite_Writer() axi_lite_writer.connect(dut, dut.clk, AXI_CTRL_BIT_WIDTH, "ctrl") yield axi_lite_writer.rst() # create and reset AXI4-Stream writer axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk, AXIS_BIT_WIDTH) yield axis_writer.rst() # create and reset AXI4-Stream reader axis_reader = AXIS_Reader() axis_reader.connect(dut, dut.clk, AXIS_BIT_WIDTH) yield axis_reader.rst() # start random toggling of axi stream reader tready cocotb.fork(toggle_signal(dut.clk, dut.m_axis_tready)) # perform a set of test. each run will generate its own random mac # addresses for i in range(N_RUNS): print("Test %d/%d" % (i + 1, N_RUNS)) yield perform_test(dut, axi_lite_writer, axis_writer, axis_reader)
def nt_recv_capture_rx_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # do not issue software reset dut.rst_sw <= 0 # reset the dut yield rstn(dut.clk, dut.rstn) # instantiate an AXI4-Stream writer, connect and reset it axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk, DATAPATH_BIT_WIDTH) yield axis_writer.rst() # generate a couple of random Ethernet packets. For each packet, generate # a 16 bit latency value and a 26 bit inter-packet time value pkts = [] latencies = [] inter_packet_times = [] for _ in range(N_PACKETS): pkts.append(gen_packet()) latencies.append(randint(0, 2**24-1)) inter_packet_times.append(randint(0, 2**28-1)) # meta and data FIFOs never become full dut.fifo_meta_full_i <= 0 dut.fifo_data_full_i <= 0 # test 0: capture disabled print("Performing test 1/%d" % (N_REPEATS+3)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, False, 0) # test 1: max capture size: 1514 byte print("Performing test 2/%d" % (N_REPEATS+3)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, 1514) # test 2: max capture size: 0 byte print("Performing test 3/%d" % (N_REPEATS+3)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, 0) # perform some more tests for random capture sizes for i in range(N_REPEATS): print("Performing test %d/%d" % (3+i, N_REPEATS+3)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, randint(64, 1514))
def nt_recv_capture_mem_write_fifo_wrapper_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # do not issue software reset dut.rst_sw <= 0 # initially we do not read or write data to the FIFO dut.rd_en_i <= 0 dut.wr_en_i <= 0 # initially do not add alignment data dut.align_i <= 0 # reset the dut yield rstn(dut.clk, dut.rstn) # wait a few cycles yield wait_n_cycles(dut.clk, 10) for i, n_words in enumerate(N_INPUT_WORDS): print("Test %d/%d" % (i + 1, len(N_INPUT_WORDS))) # generate 64 bit input data data64 = gen_input_data(n_words) # convert 64 bit input data to 512 bit output data data512 = convert_data_64_to_512(data64) # start input coroutine coroutine_in = cocotb.fork(apply_input(dut, data64)) # start ouput coroutine coroutine_out = cocotb.fork(check_output(dut, data512)) # start one coroutine for triggering aligment coroutine_align = cocotb.fork(trigger_align(dut, data64)) # wait for coroutines to complete yield coroutine_in.join() yield coroutine_out.join() yield coroutine_align.join()
def nt_recv_interpackettime_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk156, CLK_FREQ_MHZ)) # no software reset dut.rst_sw156 <= 0 # reset the DuT yield rstn(dut.clk156, dut.rstn156) # create an AXI4-Stream reader, connect and reset it axis_reader = AXIS_Reader() axis_reader.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_reader.rst() # create an AXI4-Stream writer, connect and reset it axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_writer.rst() # generate some random packets pkts = [] for _ in range(N_PACKETS): pkts.append(gen_packet()) # start random toggling of AXI4-Stream reader TREADY cocotb.fork(toggle_signal(dut.clk156, dut.m_axis_tready)) # start one coroutine to apply packets on DuT input cocotb.fork(packets_write(dut, axis_writer, pkts)) # start one coroutine to read packets on DuT output coroutine_read = cocotb.fork(packets_read(dut, axis_reader, pkts)) # start one coroutine that monitors inter-packet times cocotb.fork(monitor_inter_packet_time(dut)) # wait for coroutines to complete yield coroutine_read.join()
def nt_recv_capture_fifo_merge(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # do not issue software reset dut.rst_sw <= 0 # output fifo is never full dut.fifo_full_i <= 0 # intially not writing to input fifos dut.fifo_meta_wr_en_i <= 0 dut.fifo_data_wr_en_i <= 0 # reset the dut yield rstn(dut.clk, dut.rstn) # wait a few cycles yield wait_n_cycles(dut.clk, 5) for i in range(N_REPEATS): # print out some status print("Test %d/%d" % (i+1, N_REPEATS)) # determine random maximum capture length max_len_capture = random.randint(0, 1514) # generate packet and meta data (meta, data) = gen_input_data(max_len_capture) # start stimulus coroutine cocotb.fork(apply_input(dut, meta, data)) # start coroutine checking output coroutine_chk = cocotb.fork(check_output(dut, meta, data, max_len_capture)) # wat for checking coroutine to complete yield coroutine_chk.join()
def nt_gen_replay_top_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # no software reset dut.rst_sw <= 0 # reset dut yield rstn(dut.clk, dut.rstn) # open trace file trace = File("files/random.file") # get trace file size trace_size = trace.size() # trace file must be a multiple of the AXI data width if trace.size() % (AXI_MEM_BIT_WIDTH / 8) != 0: raise cocotb.result.TestFailure("invalid trace size") # calculate ring buffer sizes ring_buff_sizes = [] for ring_buff_size in RING_BUFF_SIZES: # size of ring buffer is determined by multiplying the size factor by # the size of the trace ring_buff_size = int(ring_buff_size * trace_size) # make sure that the ring buffer size is multiple of AXI data width if ring_buff_size % (AXI_MEM_BIT_WIDTH / 8) != 0: ring_buff_size += AXI_MEM_BIT_WIDTH/8 - \ ring_buff_size % (AXI_MEM_BIT_WIDTH/8) ring_buff_sizes.append(ring_buff_size) # create a ring buffer memory (initially of size 0) and connect it to the # DUT ring_buff = Mem(0) ring_buff.connect(dut, "ddr3") # create axi lite writer, connect and reset axi_lite_writer = AXI_Lite_Writer() axi_lite_writer.connect(dut, dut.clk, AXI_LITE_BIT_WIDTH, "ctrl") yield axi_lite_writer.rst() # create axi lite reader, connect and reset axi_lite_reader = AXI_Lite_Reader() axi_lite_reader.connect(dut, dut.clk, AXI_LITE_BIT_WIDTH, "ctrl") yield axi_lite_reader.rst() # create axi stream reader, connect and reset axis_reader = AXIS_Reader() axis_reader.connect(dut, dut.clk, AXIS_BIT_WIDTH) yield axis_reader.rst() # start the ring buffer memory main routine cocotb.fork(ring_buff.main()) # toggle m_axis_tready cocotb.fork(toggle_signal(dut.clk, dut.m_axis_tready)) # iterate over all ring buffer sizes for i, ring_buff_size in enumerate(ring_buff_sizes): # set ring buffer size ring_buff.set_size(ring_buff_size) # iterate over all addresses where ring buffer shall be located in # memory for j, ring_buff_addr in enumerate(RING_BUFF_ADDRS): # print status print("Test %d/%d" % (i * len(RING_BUFF_ADDRS) + j + 1, len(RING_BUFF_ADDRS) * len(RING_BUFF_SIZES))) print("Ring Buff Addr: 0x%x, Size: %d" % (ring_buff_addr, ring_buff_size)) # we have a total of 8 GByte of memory. Make sure the ring buffer # fits at the desired address if ring_buff_addr + ring_buff_size > 0x1FFFFFFFF: raise cocotb.result.TestFailure("ring buffer is too large") # to reduce the simulation memory footprint, provide the memory # module the first memory address that we acutally care about ring_buff.set_offset(ring_buff_addr) # configure ring buffer memory location yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_MEM_ADDR_HI, ring_buff_addr >> 32) yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_MEM_ADDR_LO, ring_buff_addr & 0xFFFFFFFF) # configure ring buffer address range yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_MEM_RANGE, ring_buff_size - 1) # configure trace size yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_TRACE_SIZE_HI, trace_size >> 32) yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_TRACE_SIZE_LO, trace_size & 0xFFFFFFFF) # reset write address pointer yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_ADDR_WR, 0x0) # make sure module initially is inactive status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) if status & 0x3 != 0: raise cocotb.reset.TestFailure("module is active") # start the module yield axi_lite_writer.write(CPUREG_OFFSET_CTRL_START, 0x1) # wait a few cycles yield wait_n_cycles(dut.clk, 10) # start writing the ring buffer cocotb.fork( ring_buff_write(dut, ring_buff, trace, ring_buff_addr, axi_lite_reader, axi_lite_writer)) # start coroutine that checks dut output coroutine_chk_out = cocotb.fork( check_output(dut, trace, axis_reader)) # wait a few cycles and make sure module is active yield wait_n_cycles(dut.clk, 10) status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) if status & 0x1 == 0x0: raise cocotb.result.TestFailure("mem read not active") if status & 0x2 == 0x0: raise cocotb.result.TestFailure("packet assembly not active") # wait for output check to complete yield coroutine_chk_out.join() # wait a few cycles yield wait_n_cycles(dut.clk, 10) # make sure module is now inactive status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) if status & 0x3 != 0x0: raise cocotb.result.TestFailure("module does not become " + "inactive") # clear the ring buffer contents ring_buff.clear() # close the trace file trace.close()
def nt_gen_timestamp_insert_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk156, CLK_FREQ_MHZ)) # no software reset dut.rst_sw156 <= 0 # reset the dut yield rstn(dut.clk156, dut.rstn156) # create an axi stream writer, connect it and reset if axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_writer.rst() # create an axi stream reader, connect it and reset if axis_reader = AXIS_Reader() axis_reader.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_reader.rst() # start the timestamp counter cocotb.fork(timestamp_counter(dut)) # generate some ip packets pkts = [] for _ in range(N_PACKETS): pkts.append(gen_packet()) # initially we insert timestamps in the packet headers dut.mode_i <= MODE_HEADER print("Test Timestamp Header") yield perform_test(dut, axis_writer, axis_reader, pkts) # then we perform one test where we do not insert any timestamps at all dut.mode_i <= MODE_DISABLED print("Test Timestamp Disabled") yield perform_test(dut, axis_writer, axis_reader, pkts) # next run some random tests with timestamp inserted at fixed byte position for i in range(N_REPEATS): # generate some ip packets pkts = [] for _ in range(N_PACKETS): pkts.append(gen_packet()) # fixed byte position dut.mode_i <= MODE_FIXED_POS # randomly choose 16 bit or 24 bit timestamp width width = randint(0, 1) # find valid timestamp positions while True: pos = randint(0, 1518) if width == 0 and (pos % 8) < 7: break elif width == 1 and (pos % 8) < 6: break # set timestamp position and width dut.pos_i <= pos dut.width_i <= width # perform the test print("Test Timestamp Fixed Pos %d/%d (Pos: %d, Width: %d)" % (i + 1, N_REPEATS, pos, width)) yield perform_test(dut, axis_writer, axis_reader, pkts)
def nt_recv_latency_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk156, CLK_FREQ_MHZ)) # no software reset dut.rst_sw156 <= 0 # reset the dut yield rstn(dut.clk156, dut.rstn156) # create an AXI4-Stream reader, connect and reset it axis_reader = AXIS_Reader() axis_reader.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_reader.rst() # create an AXI4-Stream writer, connect and reset it axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_writer.rst() # start random toggling of AXI4-Stream reader TREADY cocotb.fork(toggle_signal(dut.clk156, dut.m_axis_tready)) # set current timestamp to be static at 8421376 dut.timestamp_i <= 8421376 yield RisingEdge(dut.clk156) # generate 70% of N_PACKETS IP packets and insert random timestamp in # packet header n_packets_ip = int(0.7 * N_PACKETS) pkts = [] timestamps = [] for _ in range(n_packets_ip): pkt = gen_packet() packet_insert_random_timestamp_header(pkt, timestamps) pkts.append(pkt) # then generate 30% of N_PACKETS non-IP packets. no timestamp will be # inserted for _ in range(N_PACKETS - n_packets_ip): pkt = gen_packet(eth_only=True) pkts.append(pkt) timestamps.append(None) # shuffle pkt and timestamp lists (in same order) tmp = list(zip(pkts, timestamps)) shuffle(tmp) pkts, timestamps = zip(*tmp) # we inserted timestamps in packet header dut.mode_i <= MODE_HEADER print("Test Timestamp Header") yield perform_test(dut, axis_writer, axis_reader, pkts, timestamps) # perform another test where timestamping is disabled dut.mode_i <= MODE_DISABLED print("Test Timestamp Disabled") yield perform_test(dut, axis_writer, axis_reader, pkts, timestamps) # next run some random tests with timestamp inserted at fixed byte position for i in range(N_REPEATS): # fixed byte position dut.mode_i <= MODE_FIXED_POS # randomly choose 16 bit or 24 bit timestamp width width = randint(0, 1) # find valid timestamp positions while True: pos = randint(0, 1518) if width == 0 and (pos % 8) < 7: break elif width == 1 and (pos % 8) < 6: break # set timestamp position and width dut.pos_i <= pos dut.width_i <= width # generate some ip packets and insert random timestamps pkts = [] timestamps = [] for _ in range(N_PACKETS): pkt = gen_packet() pkt = packet_insert_random_timestamp_fixed(pkt, timestamps, pos, width) pkts.append(pkt) # perform the test print("Test Timestamp Fixed Pos %d/%d (Pos: %d, Width: %d)" % (i + 1, N_REPEATS, pos, width)) yield perform_test(dut, axis_writer, axis_reader, pkts, timestamps)
def nt_gen_rate_ctrl_top_test(dut): """Test bench main function.""" # initially module is inactive dut.active_i <= 0 # no software reset dut.rst_sw156 <= 0 # start the clock cocotb.fork(clk_gen(dut.clk156, CLK_FREQ_MHZ)) # reset the DuT yield rstn(dut.clk156, dut.rstn156) # create AXI4-Stream writer and reader axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_writer.rst() axis_reader = AXIS_Reader() axis_reader.connect(dut, dut.clk156, AXIS_BIT_WIDTH) yield axis_reader.rst() # create AXI4-Lite writer and connect to DuT axi_lite_writer = AXI_Lite_Writer() axi_lite_writer.connect(dut, dut.clk156, AXI_CTRL_BIT_WIDTH, "ctrl") yield axi_lite_writer.rst() # create AXI4-Lite reader and connect to DuT axi_lite_reader = AXI_Lite_Reader() axi_lite_reader.connect(dut, dut.clk156, AXI_CTRL_BIT_WIDTH, "ctrl") yield axi_lite_reader.rst() # initially we are always ready to receive dut.m_axis_tready <= 1 # start a coroutine that counts the number of cycles between two packets # on the output axi stream cocotb.fork(count_cycles_between_axis_transmission(dut)) print("Test 1/4") # generate some packets and inter-packet times. we start with a constant # inter-packet time of 200 cycles, more than enough to transmit each packet pkts = [] for _ in range(N_PACKETS): pkts.append((gen_packet(), 200)) # write packet data cocotb.fork(packets_write(dut, axis_writer, pkts)) # wait a little yield wait_n_cycles(dut.clk156, 500) # start the module dut.active_i <= 1 # start coroutine that checks output and wait until it completes yield cocotb.fork(packets_read(dut, axis_reader, pkts, True)) # deactive the module dut.active_i <= 0 # make sure no warning was flagged status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) assert status == 0x0 print("Test 2/4") # now generate packets of fixed size of 800 bytes. Since the datapath is # 8 byte wide, it will take exactly 100 cycles to send them. Also select # a fixed inter-packet time of 100 cycles. packets should be sent # back-to-back pkts = [] for _ in range(N_PACKETS): pkt = Ether(src="53:00:00:00:00:01", dst="53:00:00:00:00:02") pkt /= ''.join( chr(random.randint(0, 255)) for _ in range(800 - len(pkt))) pkts.append((pkt, 100)) # apply packet data cocotb.fork(packets_write(dut, axis_writer, pkts)) # wait a little yield wait_n_cycles(dut.clk156, 1000) # start the module dut.active_i <= 1 # start coroutine that checks output and wait until it completes yield cocotb.fork(packets_read(dut, axis_reader, pkts, True)) # deactive the module dut.active_i <= 0 # make sure no warning was flagged status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) assert status == 0x0 print("Test 3/4") # repeat the experiment, but decrement inter-packet time to 99 cycles. # since inter-packet time is smaller than the packet transmit time, we # should get a warning pkts = [] for _ in range(N_PACKETS): pkt = Ether(src="53:00:00:00:00:01", dst="53:00:00:00:00:02") pkt /= ''.join( chr(random.randint(0, 255)) for _ in range(800 - len(pkt))) pkts.append((pkt, 99)) # apply packet data cocotb.fork(packets_write(dut, axis_writer, pkts)) # wait a little yield wait_n_cycles(dut.clk156, 500) # start the module dut.active_i <= 1 # start coroutine that checks output and wait until it completes yield cocotb.fork(packets_read(dut, axis_reader, pkts, False)) # deactive the module dut.active_i <= 0 # make sure a warning was flagged status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) assert status == 0x1 # perform software reset to clear warning flag yield axi_lite_writer.write(CPUREG_OFFSET_RST, 0x1) # now start toggeling tready cocotb.fork(toggle_signal(dut.clk156, dut.m_axis_tready)) print("Test 4/4") # repeat the experiment, inter-packet time back at 100 cycles. since the # slave is not always ready to receive, this should cause a warning pkts = [] for _ in range(N_PACKETS): pkt = Ether(src="53:00:00:00:00:01", dst="53:00:00:00:00:02") pkt /= ''.join( chr(random.randint(0, 255)) for _ in range(800 - len(pkt))) pkts.append((pkt, 100)) # apply packet data cocotb.fork(packets_write(dut, axis_writer, pkts)) # wait a little yield wait_n_cycles(dut.clk156, 500) # start the module dut.active_i <= 1 # start coroutine that checks output and wait until it completes yield cocotb.fork(packets_read(dut, axis_reader, pkts, False)) # deactive the module dut.active_i <= 0 # make sure no warning was flagged status = yield axi_lite_reader.read(CPUREG_OFFSET_STATUS) assert status == 0x1
def nt_recv_capture_top_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # no software reset dut.rst_sw <= 0 # reset DuT yield rstn(dut.clk, dut.rstn) # create AXI4-Lite writer, connect and reset it axilite_writer = AXI_Lite_Writer() axilite_writer.connect(dut, dut.clk, AXI_CTRL_BIT_WIDTH, "ctrl") yield axilite_writer.rst() # create AXI4-Lite reader, connect and reset it axilite_reader = AXI_Lite_Reader() axilite_reader.connect(dut, dut.clk, AXI_CTRL_BIT_WIDTH, "ctrl") yield axilite_reader.rst() # create AXI4-Stream writer, connect and reset it axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk, AXIS_BIT_WIDTH) yield axis_writer.rst() # create a ring buffer memory (initially of size 0) and connect it to the # DuT ring_buff = Mem(0) ring_buff.connect(dut, "ddr3") # generate a couple of random Ethernet packets. For each packet, generate # a 16 bit latency value and a 26 bit inter-packet time value pkts = [] latencies = [] inter_packet_times = [] for _ in range(N_PACKETS): pkts.append(gen_packet()) latencies.append(random.randint(0, 2**24 - 1)) inter_packet_times.append(random.randint(0, 2**28 - 1)) # start the ring buffer memory main routine cocotb.fork(ring_buff.main()) # wait some more clock cycles yield wait_n_cycles(dut.clk, 5) # iterate over all ring buffer sizes for i, ring_buff_size in enumerate(RING_BUFF_SIZES): # set ring buffer size ring_buff.set_size(ring_buff_size) # iterate over all adderesses where ring buffer shall be located in # memory for j, ring_buff_addr in enumerate(RING_BUFF_ADDRS): # print status print("Test %d/%d (this will take a while)" % (i * len(RING_BUFF_ADDRS) + j + 1, len(RING_BUFF_ADDRS) * len(RING_BUFF_SIZES))) # we have a total of 8 GByte of memory. Make sure the ring buffer # fits at the desired address if ring_buff_addr + ring_buff_size > 0x1FFFFFFFF: raise cocotb.result.TestFailure("ring buffer is too large") # to reduce the simulation memory footprint, provide the memory # module the first memory address that we actually care about ring_buff.set_offset(ring_buff_addr) # write ring buffer memory location and address range yield axilite_writer.write(CPUREG_OFFSET_CTRL_MEM_ADDR_HI, ring_buff_addr >> 32) yield axilite_writer.write(CPUREG_OFFSET_CTRL_MEM_ADDR_LO, ring_buff_addr & 0xFFFFFFFF) yield axilite_writer.write(CPUREG_OFFSET_CTRL_MEM_RANGE, ring_buff_size - 1) # itererate over all capture lengths for max_len_capture in MAX_CAPTURE_LENS: # reset read address pointer yield axilite_writer.write(CPUREG_OFFSET_CTRL_ADDR_RD, 0x0) # set max capture length yield axilite_writer.write(CPUREG_OFFSET_CTRL_MAX_LEN_CAPTURE, max_len_capture) # start couroutine that applies packets at input cocotb.fork( packets_write(dut, axis_writer, axilite_writer, axilite_reader, pkts, latencies, inter_packet_times)) # wait a bit yield wait_n_cycles(dut.clk, 50) # start the ring buffer read coroutine and wait until it # completes yield ring_buff_read(dut, axilite_writer, axilite_reader, ring_buff, ring_buff_addr, max_len_capture, pkts, latencies, inter_packet_times) # make sure no error occured errs = yield axilite_reader.read(CPUREG_OFFSET_STATUS_ERRS) assert errs == 0x0 # make sure packet count is correct pkt_cnt = \ yield axilite_reader.read(CPUREG_OFFSET_STATUS_PKT_CNT) assert pkt_cnt == len(pkts) # make sure module is deactivated now active = yield axilite_reader.read(CPUREG_OFFSET_STATUS_ACTIVE) assert active == 0 # clear the ring buffer contents ring_buff.clear()
def nt_gen_replay_mem_read_test(dut): """Test bench main function.""" # open trace file trace = File("files/random.file") # get trace file size trace_size = trace.size() # trace file size must be a multiple of AXI data width if trace.size() % (AXI_BIT_WIDTH / 8) != 0: raise cocotb.result.TestFailure("invalid trace size") # calculate ring buffer sizes ring_buff_sizes = [] for ring_buff_size in RING_BUFF_SIZES: # size of ring buffer is determined by multiplying the size factor by # the size of the trace ring_buff_size = int(ring_buff_size * trace_size) # make sure that the ring buffer size is multiple of AXI data width if ring_buff_size % (AXI_BIT_WIDTH / 8) != 0: ring_buff_size += AXI_BIT_WIDTH/8 - ring_buff_size % \ (AXI_BIT_WIDTH/8) ring_buff_sizes.append(ring_buff_size) # create a ring buffer memory (initially of size 0) and connect it to the # DUT ring_buff = Mem(0) ring_buff.connect(dut) # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # deassert sw reset dut.rst_sw <= 0 # initially module start is not triggered dut.ctrl_start_i <= 0 # reset dut yield rstn(dut.clk, dut.rstn) # start the ring buffer memory main routine cocotb.fork(ring_buff.main()) # wait some more clock cycles yield wait_n_cycles(dut.clk, 5) # randomly toggle fifo_prog_full input signal dut.fifo_prog_full_i <= 0 cocotb.fork(toggle_signal(dut.clk, dut.fifo_prog_full_i)) # iterate over all ring buffer sizes for i, ring_buff_size in enumerate(ring_buff_sizes): # set ring buffer size ring_buff.set_size(ring_buff_size) # iterate over all adderesses where ring buffer shall be located in # memory for j, ring_buff_addr in enumerate(RING_BUFF_ADDRS): # print status print("Test %d/%d" % (i * len(RING_BUFF_ADDRS) + j + 1, len(RING_BUFF_ADDRS) * len(RING_BUFF_SIZES))) # we have a total of 8 GByte of memory. Make sure the ring buffer # fits at the desired address if ring_buff_addr + ring_buff_size > 0x1FFFFFFFF: raise cocotb.result.TestFailure("ring buffer is too large") # to reduce the simulation memory footprint, provide the memory # module the first memory address that we actually care about ring_buff.set_offset(ring_buff_addr) # apply ring buffer memory location to dut dut.ctrl_mem_addr_hi_i <= ring_buff_addr >> 32 dut.ctrl_mem_addr_lo_i <= ring_buff_addr & 0xFFFFFFFF # apply ring buffer address range to dut dut.ctrl_mem_range_i <= ring_buff_size - 1 # apply trace size to dut dut.ctrl_trace_size_hi_i <= trace_size >> 32 dut.ctrl_trace_size_lo_i <= trace_size & 0xFFFFFFFF # reset write address pointer dut.ctrl_addr_wr_i <= 0 # start reading from the ring buffer dut.ctrl_start_i <= 1 yield RisingEdge(dut.clk) dut.ctrl_start_i <= 0 yield RisingEdge(dut.clk) # start writing the ring buffer cocotb.fork(ring_buff_write(dut, ring_buff, trace)) # start checking dut output and wait until it completes yield cocotb.fork(check_output(dut, trace)).join() # clear the ring buffer contents ring_buff.clear() # close trace file trace.close()
def nt_recv_capture_rx_fifo_merge_test(dut): """Test bench main function.""" # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # do not issue software reset dut.rst_sw <= 0 # reset the dut yield rstn(dut.clk, dut.rstn) # instantiate an AXI4-Stream writer, connect and reset axis_writer = AXIS_Writer() axis_writer.connect(dut, dut.clk, DATAPATH_BIT_WIDTH) yield axis_writer.rst() # generate a couple of random Ethernet packets. For each packet, generate # a 16 bit latency value and a 26 bit inter-packet time value pkts = [] latencies = [] inter_packet_times = [] for _ in range(N_PACKETS): pkts.append(gen_packet()) latencies.append(randint(0, 2**24 - 1)) inter_packet_times.append(randint(0, 2**28 - 1)) # initially output FIFO is not full dut.fifo_full_i <= 0 # test: capture disabled print("Performing test 1/%d" % (N_REPEATS + 5)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, False, 0) # test: max capture size: 1514 byte print("Performing test 2/%d" % (N_REPEATS + 5)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, 1514) # test: max capture size: 0 byte print("Performing test 3/%d" % (N_REPEATS + 5)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, 0) # perform some more tests for random capture sizes for i in range(N_REPEATS): print("Performing test %d/%d" % (3 + i, N_REPEATS + 5)) yield perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, randint(64, 1514)) # now mark the fifo as full dut.fifo_full_i <= 1 # perform another test and check data fifo error output signal # should become full print("Performing test %d/%d (no status output)" % (N_REPEATS + 4, N_REPEATS + 5)) cocotb.fork( perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, 1514)) # wait until all packets have been applied on AXI stream interface pkt_cnt = 0 while pkt_cnt < len(pkts): yield RisingEdge(dut.clk) if int(dut.s_axis_tvalid) and int(dut.s_axis_tready) and \ int(dut.s_axis_tlast): pkt_cnt += 1 # make sure the data fifo full error signal is asserted assert int(dut.err_data_fifo_full_o) # perform reset dut.rst_sw <= 1 yield RisingEdge(dut.clk) dut.rst_sw <= 0 yield RisingEdge(dut.clk) # perform one final test to check whether the meta data fifo error signal # is asserted when the fifo becomes full print("Performing test %d/%d (no status output)" % (N_REPEATS + 5, N_REPEATS + 5)) cocotb.fork( perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, True, 0)) # wait until all packets have been applied on AXI stream interface pkt_cnt = 0 while pkt_cnt < len(pkts): yield RisingEdge(dut.clk) if int(dut.s_axis_tvalid) and int(dut.s_axis_tready) and \ int(dut.s_axis_tlast): pkt_cnt += 1 # make sure the meta fifo full error signal is asserted assert int(dut.err_meta_fifo_full_o)
def nt_recv_capture_mem_write_test(dut): """Test bench main function.""" # open file with random content try: f = File("files/random.file") except IOError: raise cocotb.result.TestFailure("Generate input data by calling " + "'./create_random.py' in 'files' " + "folder!") # file size must be a multiple of AXI data width if f.size() % (BIT_WIDTH_MEM_WRITE / 8) != 0: raise cocotb.result.TestFailure("invalid input data size") # create a ring buffer memory (initially of size 0) and connect it to the # DuT ring_buff = Mem(0) ring_buff.connect(dut) # start the clock cocotb.fork(clk_gen(dut.clk, CLK_FREQ_MHZ)) # deassert sw reset dut.rst_sw <= 0 # initially module is disabled dut.active_i <= 0 # initially no FIFO flush dut.flush_i <= 0 # reset DuT yield rstn(dut.clk, dut.rstn) # start the ring buffer memory main routine cocotb.fork(ring_buff.main()) # wait some more clock cycles yield wait_n_cycles(dut.clk, 5) # iterate over all ring buffer sizes for i, ring_buff_size in enumerate(RING_BUFF_SIZES): # set ring buffer size ring_buff.set_size(ring_buff_size) # iterate over all adderesses where ring buffer shall be located in # memory for j, ring_buff_addr in enumerate(RING_BUFF_ADDRS): # print status print("Test %d/%d" % (i * len(RING_BUFF_ADDRS) + j + 1, len(RING_BUFF_ADDRS) * len(RING_BUFF_SIZES))) # we have a total of 8 GByte of memory. Make sure the ring buffer # fits at the desired address if ring_buff_addr + ring_buff_size > 0x1FFFFFFFF: raise cocotb.result.TestFailure("ring buffer is too large") # to reduce the simulation memory footprint, provide the memory # module the first memory address that we actually care about ring_buff.set_offset(ring_buff_addr) # apply ring buffer memory location to dut dut.mem_addr_hi_i <= ring_buff_addr >> 32 dut.mem_addr_lo_i <= ring_buff_addr & 0xFFFFFFFF # apply ring buffer address range to dut dut.mem_range_i <= ring_buff_size - 1 # reset read address pointer dut.addr_rd_i <= 0 # start a couroutine that applies input data cocotb.fork(apply_input(dut, f)) # wait a few clock cycles yield wait_n_cycles(dut.clk, 10) # start the ring buffer read coroutine and wait until it completes yield ring_buff_read(dut, ring_buff, f) # clear the ring buffer contents ring_buff.clear() # close file f.close()