def apply_input(dut, meta, data):
    """Apply meta data and packet data as DUT stimulus.

    Meta data is written to the input meta data FIFO, packet data is written
    to the input packet data FIFO.
    """
    # data word index
    i = 0

    # iterate over meta data words
    for m in meta:
        # get the capture length
        len_capture = (m >> 64) & 0x7FF

        # calculate the number of 64 bit data words
        if len_capture % 8 == 0:
            len_capture_words = len_capture / 8
        else:
            len_capture_words = len_capture / 8 + 1

        # apply data words at DUT input
        for _ in range(len_capture_words):
            # get data word and increment index
            d = data[i]
            i += 1

            # make sure input data fifo is not full
            check_value("fifo_data_full_i", dut.fifo_data_full_o, 0x0)

            # apply data word
            dut.fifo_data_din_i <= d
            dut.fifo_data_wr_en_i <= 1
            yield RisingEdge(dut.clk)

        # done writing data
        dut.fifo_data_wr_en_i <= 0

        # wait a random number of cycles until applying the meta data word
        yield wait_n_cycles(dut.clk, random.randint(0, 10))

        # make sure input meta data fifo is not full
        check_value("fifo_meta_full_o", dut.fifo_meta_full_o, 0x0)

        # apply meta data word
        dut.fifo_meta_din_i <= m
        dut.fifo_meta_wr_en_i <= 1
        yield RisingEdge(dut.clk)

        # done applying meta data
        dut.fifo_meta_wr_en_i <= 0

        # wait a random number of cycles again
        yield wait_n_cycles(dut.clk, random.randint(0, 10))
Beispiel #2
0
def perform_test(dut, axis_writer, pkts, latencies, inter_packet_times, active,
                 max_len_capture):
    """Perform a test run for specific capture parameters."""
    # enable/disable capture
    dut.active_i <= active

    # set per-packet capture length
    dut.max_len_capture_i <= max_len_capture

    # wait a few cycles
    yield wait_n_cycles(dut.clk, 5)

    # if capture is enabled, module shall be active now. otherwise it should
    # remain deactivated
    check_value("active_o", dut.active_o, active)

    # start writing packets to DuT input
    coroutine_pkts_write = cocotb.fork(packets_write(dut, axis_writer, pkts,
                                                     latencies,
                                                     inter_packet_times))

    # start coroutine that checks module output
    coroutine_check_output = cocotb.fork(check_output(dut, pkts, latencies,
                                                      inter_packet_times))

    # wait for coroutines to complete
    yield coroutine_pkts_write.join()
    yield coroutine_check_output.join()

    # disable module
    dut.active_i <= 0

    # wait a few cycles
    yield wait_n_cycles(dut.clk, 3)

    # make sure module is now inactive
    check_value("active_o", dut.active_o, 0x0)
Beispiel #3
0
def check_output(dut, trace):
    """Check data written to the output FIFO for correctness.

    The coroutine monitors the data written to the FIFO and checks whether it
    matches the data of the input trace file.
    """
    # get trace size
    trace_size = trace.size()

    # check data written to fifo for correctness
    for i in range(trace_size * 8 / AXI_BIT_WIDTH):
        # wait for fifo wr enable
        while True:
            yield RisingEdge(dut.clk)

            # make sure module active status signal is high
            check_value("status_active_o", int(dut.status_active_o), 1)

            if int(dut.fifo_wr_en_o):
                # output fifo data is valid
                break

        # the order of the 8 byte words is reversed in the 64 byte output word
        output = (int(dut.fifo_din_o) & 2**64 - 1) << 448
        output |= ((int(dut.fifo_din_o) >> 64) & 2**64 - 1) << 384
        output |= ((int(dut.fifo_din_o) >> 128) & 2**64 - 1) << 320
        output |= ((int(dut.fifo_din_o) >> 192) & 2**64 - 1) << 256
        output |= ((int(dut.fifo_din_o) >> 256) & 2**64 - 1) << 192
        output |= ((int(dut.fifo_din_o) >> 320) & 2**64 - 1) << 128
        output |= ((int(dut.fifo_din_o) >> 384) & 2**64 - 1) << 64
        output |= (int(dut.fifo_din_o) >> 448) & 2**64 - 1

        # get exepcted output
        output_ref = trace.read_reverse_byte_order(i * AXI_BIT_WIDTH / 8,
                                                   AXI_BIT_WIDTH / 8)

        # make sure values match
        check_value("fifo_din_o", output_ref, output)

    # wait one clock cycle and make sure active signal is low then
    yield RisingEdge(dut.clk)
    check_value("status_active_o", int(dut.status_active_o), 0)
Beispiel #4
0
def check_output(dut, trace, axis_reader):
    """Check whether the DUT output is the one that is expected.

    Based on a given trace replay file, the coroutine constructs the expected
    output behavior of the DUT and compares it to the actual values.
    """
    # get trace size
    trace_size = trace.size()

    # initialize address used to index memory-mapped trace file
    addr = 0

    while addr < trace_size:
        # read 8 byte from trace file. contains packet meta data
        meta = trace.read_reverse_byte_order(addr, 8)
        addr += 8

        if meta == 2**64 - 1:
            # the overall trace data has to be 512 bit aligned. If the actual
            # trace size is smaller, we can add padding at the end of the
            # trace (in multiples of 64 bit words). all bits of the padding
            # data have to be set to 1
            continue

        # extract meta data
        meta_delta_t = meta & 2**32 - 1
        meta_len_snap = (meta >> 32) & 2**11 - 1
        meta_len_wire = (meta >> 48) & 2**11 - 1

        # read packet data from trace file
        data = trace.read(addr, meta_len_snap)

        # increase address. packet data is aligned to 8 byte aligned
        if meta_len_snap % 8 == 0:
            addr += meta_len_snap
        else:
            addr += 8 * (meta_len_snap / 8 + 1)

        # if number of bytes on the wire is larger than the number of snap
        # bytes, add zero bytes as padding
        for _ in range(meta_len_wire - meta_len_snap):
            data <<= 8

        # create reference ethernet frame from the read data
        data = "%x" % data
        data = data.zfill(meta_len_wire)
        frame_ref = Ether(binascii.unhexlify(data))

        # read arriving frame from AXI4-Stream
        (tdata, tkeep, tuser) = yield axis_reader.read()

        # convert AXI4-Stream data to ethernet frame
        frame_recv = axis_data_to_packet(tdata, tkeep, AXIS_BIT_WIDTH)

        # make sure frames match
        if str(frame_ref) != str(frame_recv):
            raise cocotb.result.TestFailure("received wrong data")

        # inter-packet time is located in first tuser word
        meta_delta_t_recv = tuser[0] & 2**32 - 1

        # make sure the inter-packet time matches the expected one
        if meta_delta_t != meta_delta_t_recv:
            raise cocotb.result.TestFailure("wrong timing information")

        # all other tuser fields must be set to zero
        if any(v != 0 for v in tuser[2:]):
            raise cocotb.result.TestFailure("invalid tuser data")

    # wait some more cycles after last packet. there should not be any data on
    # the axi stream anymore
    for _ in range(1000):
        yield RisingEdge(dut.clk)
        check_value("m_axis_tvalid", dut.m_axis_tvalid, 0)
Beispiel #5
0
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)
Beispiel #6
0
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)