def packets_read(dut, axis_reader, pkts_ref, timestamps): """Evaluate data at DuT output and validate correct behavior.""" # read as many packets as we originally generated for i, pkt_ref in enumerate(pkts_ref): # read axi stream data (tdata, tkeep, _) = yield axis_reader.read() # convert axi stream data to scapy packet pkt = axis_data_to_packet(tdata, tkeep, AXIS_BIT_WIDTH) # check if sent and received packets match and if (possibly) inserted # timestamps match if int(dut.mode_i) == MODE_DISABLED: # timestamping is disabled, received and sent packets must be # identical valid = str(pkt) == str(pkt_ref) elif int(dut.mode_i) == MODE_HEADER: # timestamp is located in packet header valid = validate_packet_timestamp_header(pkt_ref, pkt, timestamps[i]) elif int(dut.mode_i) == MODE_FIXED_POS: # timestamp is loacted at fixed byte position valid = validate_packet_timestamp_fixed(dut, pkt_ref, pkt, timestamps[i]) else: # this should never happen assert False if not valid: raise cocotb.result.TestFailure( ("Packet #%d: received invalid " + "packet data or timestamp") % i) # print progress print_progress(i, N_PACKETS)
def packets_read(dut, axis_reader, pkts_ref, check_timing): """Check DuT output for correctness.""" p = None for i, (pkt_ref, inter_packet_cycles_ref) in enumerate(pkts_ref): # read AXI4-Stream data (tdata, tkeep, _) = yield axis_reader.read() # convert AXI4-Stream data to scapy packet pkt = axis_data_to_packet(tdata, tkeep, AXIS_BIT_WIDTH) # make sure packets match if str(pkt) != str(pkt_ref): raise cocotb.result.TestFailure("Packet #%d: wrong data" % i) # get cycles since between transmissions cycles_transmission = cntr_cycles_between_axis_transmission if check_timing and i > 0 \ and cntr_cycles_between_axis_transmission != p: raise cocotb.result.TestFailure( ("Packet #%d: wrong timing, " + "Cycles IS: %d " + "Cycles Expected %d ") % (i, cycles_transmission, p)) p = inter_packet_cycles_ref # print progress print_progress(i, N_PACKETS)
def check_output(dut, meta_ref, data_ref, max_capture_len): """Verify that the DUT's output is correct.""" # data word index j = 0 # iterate over meta data words for i, m_ref in enumerate(meta_ref): # wait until fifo output becomes valid while True: yield RisingEdge(dut.clk) if int(dut.fifo_wr_en_o): break # read the meta data word m = int(dut.fifo_din_o) # make sure meta data word matches the expected one (bits 74:64 # contain the packet capture length, which is not passed to software) if m != m_ref & 0xFFFFFFFFFFFFFFFF: raise cocotb.result.TestFailure("Packet #%d: invalid meta data" % i) # get the wire length len_wire = (m >> 53) & 0x7FF # calculate the capture length len_capture = min(len_wire, max_capture_len) # calculate how many data words we are expecting if len_capture % 8 == 0: len_capture_words = len_capture / 8 else: len_capture_words = len_capture / 8 + 1 for _ in range(len_capture_words): # get the reference data word and increment index d_ref = data_ref[j] j += 1 # wait until fifo output becomes valid while True: yield RisingEdge(dut.clk) if int(dut.fifo_wr_en_o): break # read data word d = int(dut.fifo_din_o) # make sure fifo output data matches the data word we are expecting if d != d_ref: raise cocotb.result.TestFailure("Packet #%d: invalid data" % i) # print progress print_progress(i, len(meta_ref)) # ensure that all data has been read if j != len(data_ref): raise cocotb.result.TestFailure("did not read all data")
def packets_read(dut, axis_reader, pkts_ref): """Evaluate correct packet data at DuT output.""" # we must read as many packets as we appyed at the input for i, pkt_ref in enumerate(pkts_ref): # read AXI4-Stream data (tdata, tkeep, tuser) = yield axis_reader.read() # convert AXI4-Stream data to scapy packet pkt = axis_data_to_packet(tdata, tkeep, AXIS_BIT_WIDTH) # make sure read packet matches the one we expected if str(pkt) != str(pkt_ref): raise cocotb.result.TestFailure(("Packet #%d: read invalid " + "packet data") % i) # make sure that all TUSER values except the last one are set to zero if any(v != 0 for v in tuser[1:len(tuser)-1]): raise cocotb.result.TestFailure(("Packet #%d: invalid TUSER " + "value (!= 0)") % i) # the 25 LSB of the last TUSER value must match the value we applied on # the input if tuser[-1] & 0x1FFFFFF != TUSER_LSB: raise cocotb.result.TestFailure(("Packet #%d: invalid TUSER " + "value (!= input)") % i) # print progress print_progress(i, N_PACKETS) # inter-packet time is a relative number. start evaluation with second # packet if i == 0: continue # extract inter-packet time from TUSER inter_packet_cycles = tuser[len(tuser)-1] >> 25 # get the expected inter-packet time from FIFO inter_packet_cycles_ref = inter_packet_cycles_monitor.pop(0) # make sure the extracted inter-packet time matches the one monitored # on the DuT output if inter_packet_cycles != inter_packet_cycles_ref: raise cocotb.result.TestFailure(("Packet #%d: invalid " + "inter-packet time " + "(Expected: %d, Is: %d)") % (i, inter_packet_cycles_ref, inter_packet_cycles))
def frames_read(dut, axis_reader, frames_ref): """Evaluate data at DuT output and validates correct behavior.""" # iterate over the list of frames that we are expecting to read for i, frame_ref in enumerate(frames_ref): # read AXI4-Stream data (tdata, tkeep, _) = yield axis_reader.read() # convert AXI4-Stream data to scapy frame frame = axis_data_to_packet(tdata, tkeep, AXIS_BIT_WIDTH) # check if written and read frames are equal if str(frame) != str(frame_ref): raise cocotb.result.TestFailure("Frame #%d: invalid data" % i) # print progress print_progress(i, N_FRAMES)
def packets_read(dut, axis_reader, pkts_ref, timestamps_ref): """Evaluate data at DuT output and validate correct behavior.""" # read as many packets as we originally generated for i, pkt_ref in enumerate(pkts_ref): # read AXI4-Stream data (tdata, tkeep, tuser) = yield axis_reader.read() # print progress print_progress(i, N_PACKETS) # convert AXI4-Stream data to scapy packet pkt = axis_data_to_packet(tdata, tkeep, AXIS_BIT_WIDTH) # make sure received packet matches expected packet if str(pkt) != str(pkt_ref): raise cocotb.result.TestFailure( ("Packet #%d: received invalid " + "packet data") % i) # make sure that all tuser values except the last one are set to zero if any(v != 0 for v in tuser[1:-1]): raise cocotb.result.TestFailure("Packet #%d: invalid TUSER value" % i) if int(dut.mode_i) == MODE_HEADER: # latency timestamp is saved in IP packet header. latency values # must be extracted for all IP packets if pkt_ref.type == 0x800 or pkt_ref.type == 0x86dd: # latency value provided at output? latency_valid = tuser[-1] >> 24 if latency_valid == 0: raise cocotb.result.TestFailure( ("Packet #%d: no " + "latency value in " + "output") % i) # get latency value latency = tuser[-1] & 0xFFFFFF # calculate reference latency timestamp_cur = int(dut.timestamp_i) & 0xFFFF if timestamp_cur > timestamps_ref[i]: latency_ref = timestamp_cur - timestamps_ref[i] else: latency_ref = 0xFFFF - timestamps_ref[i] + \ timestamp_cur + 1 # make sure latency values match if latency != latency_ref: raise cocotb.result.TestFailure( ("Packet #%d: wrong " + "latency value") % i) else: # non latency value must be provided on output for non-IP # packets if tuser[-1] != 0: raise cocotb.result.TestFailure( ("Packet #%d: latency " + "value on output") % i) elif int(dut.mode_i) == MODE_FIXED_POS: # latency timestamp is located at a fixed byte position in the # packet # is packet long enough to contain a timestamp? if int(dut.width_i) == 0: # timestamp is 16 bit wide if len(pkt_ref) < int(dut.pos_i) + 2: # not long enough, make sure that no latency value is # provided if tuser[-1] != 0: raise cocotb.result.TestFailure( ("Packet #%d: " + "latency value on " + "output") % i) # ensure that we did not generate a timestamp for this # packet assert timestamps_ref[i] is None # nothing more to do for this packet continue else: # timestamp is 24 bit wide if len(pkt_ref) < int(dut.pos_i) + 3: # not long enough, make sure that no latency value is # provided if tuser[-1] != 0: raise cocotb.result.TestFailure( ("Packet #%d: " + "latency value on " + "output") % i) # ensure that we did not generate a timestamp for this # packet assert timestamps_ref[i] is None # nothing more to do for this packet continue # make sure latency value is provided at output latency_valid = tuser[-1] >> 24 if latency_valid == 0: raise cocotb.result.TestFailure( ("Packet #%d: no " + "latency value in " + "output") % i) # get latency value latency = tuser[-1] & 0xFFFFFF # calculate reference latency if int(dut.width_i) == 0: # 16 bit timestamp timestamp_cur = int(dut.timestamp_i) & 0xFFFF if timestamp_cur > timestamps_ref[i]: latency_ref = timestamp_cur - timestamps_ref[i] else: latency_ref = 0xFFFF - timestamps_ref[i] + \ timestamp_cur + 1 else: # 24 bit timestamp timestamp_cur = int(dut.timestamp_i) if timestamp_cur > timestamps_ref[i]: latency_ref = timestamp_cur - timestamps_ref[i] else: latency_ref = 0xFFFFFF - timestamps_ref[i] + \ timestamp_cur + 1 # make sure latency values match if latency != latency_ref: raise cocotb.result.TestFailure( ("Packet #%d: wrong " + "latency value") % i) elif int(dut.mode_i) == MODE_DISABLED: # timestamping is disabled # all bits of the last tuser value must be set to zero if tuser[-1] != 0: raise cocotb.result.TestFailure(("Packet #%d: latency value " "in output") % i) else: # this should never happen assert False
def check_output(dut, pkts_ref, latencies_ref, inter_packet_times_ref): """Check DuT output for correctness.""" # check whether capturing is enabled enabled = int(dut.active_i) == 1 if not enabled: # packet data capturing is disabled. make sure that the module does not # output any data pkt_cnt = 0 while pkt_cnt < len(pkts_ref): # the module should not write any data to the FIFOs at all yield RisingEdge(dut.clk) assert int(dut.fifo_meta_wr_en_o) == 0 assert int(dut.fifo_data_wr_en_o) == 0 assert int(dut.pkt_cnt_o) == 0 if int(dut.s_axis_tvalid) and int(dut.s_axis_tready) and \ int(dut.s_axis_tlast): # one full packet has been applied at DuT input -> print # progress and increment packet counter print_progress(pkt_cnt, N_PACKETS) pkt_cnt += 1 # make sure packet counter is still at zero check_value("pkt_cnt_o", dut.pkt_cnt_o, 0x0) else: # packet capture is enabled # get the configured maximum capture length max_len_capture = int(dut.max_len_capture_i) data = [] # iterate over all reference packets for i, pkt_ref in enumerate(pkts_ref): # calculate the expected capture length meta_len_capture_ref = min(len(pkt_ref), max_len_capture) # each data FIFO word is 8 bytes wide, calculate number of data # words that shall be written for the captured data if meta_len_capture_ref % 8 == 0: n_words_ref = meta_len_capture_ref / 8 else: n_words_ref = (meta_len_capture_ref / 8) + 1 while True: yield RisingEdge(dut.clk) if int(dut.fifo_meta_wr_en_o): # meta data is written to FIFO in this cycle # get meta data meta_data = int(dut.fifo_meta_din_o) # make sure that the correct number of data words have been # written to the FIFO assert len(data) == n_words_ref # extract meta data meta_latency = meta_data & 0xFFFFFF meta_latency_valid = (meta_data >> 24) & 0x1 meta_interpackettime = (meta_data >> 25) & 0xFFFFFFF meta_len_wire = (meta_data >> 53) & 0x7FF meta_len_capture = (meta_data >> 64) & 0x7FF # make sure the latency is marked valid if meta_latency_valid != 0x1: raise cocotb.result.TestFailure(("Packet #%d: " + "Latency value not " + "valid") % i) # make sure latency matches reference value if latencies_ref[i] != meta_latency: raise cocotb.result.TestFailure(("Packet #%d: " + "incorrect latency") % i) # make sure inter-packet time matches reference value if inter_packet_times_ref[i] != meta_interpackettime: raise cocotb.result.TestFailure(("Packet #%d: " + "incorrect inter-" + "packet time") % i) # make sure wire length matches packet length if len(pkt_ref) != meta_len_wire: raise cocotb.result.TestFailure(("Packet #%d: " + "invalid wire " + "length") % i) # make sure capture length matches expected value if meta_len_capture != meta_len_capture_ref: raise cocotb.result.TestFailure(("Packet #%d: " + "invalid capture" + "length") % i) # create packet from captured data if meta_len_capture % (DATAPATH_BIT_WIDTH/8) == 0: pkt = axis_data_to_packet(data, 2**(DATAPATH_BIT_WIDTH/8)-1, DATAPATH_BIT_WIDTH) else: pkt = axis_data_to_packet(data, 2**(meta_len_capture % 8)-1, DATAPATH_BIT_WIDTH) # make sure packet data matches the exepcted packet data if str(pkt)[0:meta_len_capture] != \ str(pkt_ref)[0:meta_len_capture]: raise cocotb.result.TestFailure(("Packet #%d: " + "invalid data") % i) # delete captured data data = [] if int(dut.fifo_data_wr_en_o): # data is being written to the data FIFO data.append(int(dut.fifo_data_din_o)) if int(dut.fifo_meta_wr_en_o): # meta data has been written and checked -> we are done for # this packet. print_progress(i, N_PACKETS) break # make sure packet counter value is correct check_value("pkt_cnt_o", dut.pkt_cnt_o, len(pkts_ref)) # make sure no errors are flagged by the DuT check_value("err_data_fifo_full_o", dut.err_data_fifo_full_o, 0x0) check_value("err_meta_fifo_full_o", dut.err_meta_fifo_full_o, 0x0)
def check_output(dut, pkts_ref, latencies_ref, inter_packet_times_ref): """Check DuT output for correctness.""" # check whether capturing is enabled enabled = int(dut.active_i) == 1 if not enabled: # packet data capturing is disabled. make sure that the module does not # output any data pkt_cnt = 0 while pkt_cnt < len(pkts_ref): # the module should not write any data to the output FIFO at all yield RisingEdge(dut.clk) assert int(dut.fifo_wr_en_o) == 0 assert int(dut.pkt_cnt_o) == 0 if int(dut.s_axis_tvalid) and int(dut.s_axis_tready) and \ int(dut.s_axis_tlast): # one full packet has been applied at DuT input -> print # progress and increment packet counter print_progress(pkt_cnt, N_PACKETS) pkt_cnt += 1 if pkt_cnt == len(pkts_ref): # all packets have been applied -> done! break # make sure packet counter is still at zero check_value("pkt_cnt_o", dut.pkt_cnt_o, 0x0) else: # packet capture is enabled # get the configured maximum capture length max_len_capture = int(dut.max_len_capture_i) # iterate over all reference packets for i, pkt_ref in enumerate(pkts_ref): # get the packet's capture length len_capture = min(len(pkt_ref), max_len_capture) # wait for fifo write output signal to become high while True: yield RisingEdge(dut.clk) if int(dut.fifo_wr_en_o): break # get meta data meta_data = int(dut.fifo_din_o) # extract meta data meta_latency = meta_data & 0xFFFFFF meta_latency_valid = (meta_data >> 24) & 0x1 meta_interpackettime = (meta_data >> 25) & 0xFFFFFFF meta_len_wire = (meta_data >> 53) & 0x7FF # make sure the latency is marked valid if meta_latency_valid != 0x1: raise cocotb.result.TestFailure( ("Packet #%d: " + "Latency value not " + "valid") % i) if latencies_ref[i] != meta_latency: raise cocotb.result.TestFailure( ("Packet #%d: " + "incorrect latency") % i) # make sure inter-packet time matches reference value if inter_packet_times_ref[i] != meta_interpackettime: raise cocotb.result.TestFailure( ("Packet #%d: " + "incorrect inter-" + "packet time") % i) # make sure wire length matches packet length if len(pkt_ref) != meta_len_wire: raise cocotb.result.TestFailure( ("Packet #%d: " + "invalid wire " + "length") % i) # calculate number of 8 byte packet data words if len_capture % 8 == 0: len_capture_words = len_capture / 8 else: len_capture_words = len_capture / 8 + 1 # read as many data words as specified by capture length data = [] for _ in range(len_capture_words): # wait for FIFO write output signal to become high while True: yield RisingEdge(dut.clk) if int(dut.fifo_wr_en_o): break # read data word data.append(int(dut.fifo_din_o)) # create packet from captured data if len_capture % (DATAPATH_BIT_WIDTH / 8) == 0: pkt = axis_data_to_packet(data, 2**(DATAPATH_BIT_WIDTH / 8) - 1, DATAPATH_BIT_WIDTH) else: pkt = axis_data_to_packet(data, 2**(len_capture % 8) - 1, DATAPATH_BIT_WIDTH) # make sure packet data matches the exepcted packet data if str(pkt)[0:len_capture] != \ str(pkt_ref)[0:len_capture]: raise cocotb.result.TestFailure( ("Packet #%d:" + "invalid data") % i) # print progress print_progress(i, N_PACKETS) # make sure packet counter value is correct check_value("pkt_cnt_o", dut.pkt_cnt_o, len(pkts_ref)) # make sure no errors are flagged by the DuT check_value("err_data_fifo_full_o", dut.err_data_fifo_full_o, 0x0) check_value("err_meta_fifo_full_o", dut.err_meta_fifo_full_o, 0x0)