Exemplo n.º 1
0
async def test_4kB_boundary(dut):
    """
    Check that the driver raises an error when trying to cross a 4kB boundary
    """

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, ram_stop = get_parameters(dut)

    await setup_dut(dut)

    for rw in ("Read", "Write"):
        burst_length = randint(2, 256)
        base = randrange(ram_start, ram_stop - 4096, 4096)
        offset = randrange(-(burst_length - 1) * data_width, 0, data_width)
        address = base + offset
        write_values = \
            [randrange(0, 2**(data_width * 8)) for i in range(burst_length)]

        try:
            if rw == "Read":
                await axim.read(address, burst_length)
            else:
                await axim.write(address, write_values)

            raise TestFailure(
                "{} from {:#x} to {:#x} crosses a 4kB boundary, but the "
                "driver allowed it".format(
                    rw, address, address + (burst_length - 1) * data_width))
        except ValueError:
            pass
Exemplo n.º 2
0
async def test_incr_burst(dut, size, return_rresp):
    """Test burst reads/writes"""

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, ram_stop = get_parameters(dut)
    size = size if size else data_width

    await setup_dut(dut)

    burst_length = randrange(2, 256)
    base = randrange(ram_start, ram_stop, 4096)
    offset = randrange(0, 4096 - (burst_length - 1) * size, size)
    address = base + offset
    write_values = [randrange(0, 2**(size * 8)) for i in range(burst_length)]

    # Make strobe one item less than data, to test also that driver behavior
    strobes = [randrange(0, 2**size) for i in range(len(write_values) - 1)]

    previous_values = await axim.read(address, len(write_values), size=size)
    await axim.write(address, write_values, byte_enable=strobes, size=size)
    read_values = await axim.read(address,
                                  len(write_values),
                                  return_rresp=return_rresp,
                                  size=size)

    if return_rresp:
        read_values, rresp_list = zip(*read_values)
        for i, rresp in enumerate(rresp_list):
            if rresp is not AXIxRESP.OKAY:
                raise TestFailure(
                    "Read at beat {}/{} with starting address {:#x} failed "
                    "with RRESP {} ({})".format(i + 1, len(rresp_list),
                                                address, rresp.value,
                                                rresp.name))

    strobes += [strobes[-1]]
    expected_values = \
        [add_wstrb_mask(size, previous_value, write_value, wstrb)
         for previous_value, write_value, wstrb
         in zip(previous_values, write_values, strobes)]

    for i in range(len(read_values)):
        if expected_values[i] != read_values[i]:
            raise TestFailure(
                "Read {:#x} at beat {}/{} with starting address {:#x}, but "
                "was expecting {:#x} ({:#x} with {:#x} as strobe and {:#x} as "
                "previous value)".format(read_values[i].integer, i + 1,
                                         burst_length, address,
                                         expected_values[i], write_values[i],
                                         strobes[i],
                                         previous_values[i].integer))
Exemplo n.º 3
0
async def test_simultaneous(dut, sync, num=5):
    """Test simultaneous reads/writes"""

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, _ = get_parameters(dut)

    await setup_dut(dut)

    # Avoid crossing the 4kB boundary by using just the first 4kB block
    base_address = randrange(ram_start,
                             ram_start + 4096 - 2 * num * data_width,
                             data_width)

    # Clear the memory cells
    await axim.write(base_address, [0] * num)

    addresses = [base_address + i * data_width for i in range(num)]
    write_values = [randrange(0, 2**(data_width * 8)) for i in range(num)]

    writers = [
        axim.write(address, value, sync=sync)
        for address, value in zip(addresses, write_values)
    ]

    await Combine(*writers)

    readers = [
        cocotb.fork(axim.read(address, sync=sync)) for address in addresses
    ]

    dummy_addrs = [base_address + (num + i) * data_width for i in range(num)]
    dummy_writers = [
        cocotb.fork(axim.write(address, value, sync=sync))
        for address, value in zip(dummy_addrs, write_values)
    ]

    read_values = []
    for reader in readers:
        read_values.append((await Join(reader))[0])
    await Combine(*[Join(writer) for writer in dummy_writers])

    for i, (written, read) in enumerate(zip(write_values, read_values)):
        if written != read:
            raise TestFailure("#{}: wrote {:#x} but read back {:#x}".format(
                i, written, read.integer))
Exemplo n.º 4
0
async def test_illegal_operations(dut):
    """Test whether illegal operations are correctly refused by the driver"""

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, _ = get_parameters(dut)

    illegal_operations = (
        (AXIBurst.INCR, -1, None),
        (AXIBurst.INCR, 0, None),
        (AXIBurst.FIXED, 17, None),
        (AXIBurst.INCR, 257, None),
        (AXIBurst.WRAP, 3, None),
        (AXIBurst.INCR, 4, -1),
        (AXIBurst.INCR, 4, data_width - 1),
        (AXIBurst.INCR, 4, data_width * 2),
    )

    await setup_dut(dut)

    for rw in ("Read", "Write"):
        for burst, length, size in illegal_operations:
            try:
                if rw == "Read":
                    await axim.read(ram_start, length, size=size, burst=burst)
                else:
                    values = [
                        randrange(0, 2**(data_width * 8))
                        for i in range(length)
                    ]
                    await axim.write(ram_start, values, size=size, burst=burst)

                raise TestFailure(
                    "{} with length={}, size={} and burst={} has been "
                    "performed by the driver, but it is an illegal "
                    "operation".format(rw, length, size, burst.name))

            except ValueError:
                pass
Exemplo n.º 5
0
async def test_fixed_wrap_burst(dut, size, burst_length=16):
    """Test FIXED and WRAP read/writes"""

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, ram_stop = get_parameters(dut)
    size = size if size else data_width

    await setup_dut(dut)

    base = randrange(ram_start, ram_stop, 4096)
    offset = randrange(0, 4096 - (burst_length - 1) * size, size)
    address = base + offset

    for burst in (AXIBurst.FIXED, AXIBurst.WRAP):

        write_values = \
            [randrange(0, 2**(size * 8)) for i in range(burst_length)]

        await axim.write(address, write_values, burst=burst, size=size)

        if burst is AXIBurst.FIXED:
            # A FIXED write on a memory is like writing the last element,
            # reading it with a FIXED burst returns always the same value.
            expected_values = [write_values[-1]] * burst_length
        else:
            # Regardless of the boundary, reading with a WRAP from the same
            # address with the same length returns the same sequence.
            # This RAM implementation does not support WRAP bursts and treats
            # them as INCR.
            expected_values = write_values

        read_values = await axim.read(address,
                                      burst_length,
                                      burst=burst,
                                      size=size)

        compare_read_values(expected_values, read_values, burst, burst_length,
                            address)
Exemplo n.º 6
0
async def test_narrow_burst(dut):
    """Test that narrow writes and full reads match"""

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, ram_stop = get_parameters(dut)

    await setup_dut(dut)

    burst_length = (randrange(2, 256) // 2) * 2
    address = ram_start
    write_values = \
        [randrange(0, 2**(data_width * 8 // 2)) for i in range(burst_length)]

    await axim.write(address, write_values, size=data_width // 2)

    read_values = await axim.read(address, burst_length // 2)

    expected_values = [
        write_values[i + 1] << 16 | write_values[i]
        for i in range(0, burst_length // 2, 2)
    ]

    compare_read_values(expected_values, read_values, AXIBurst.INCR,
                        burst_length // 2, address)
Exemplo n.º 7
0
async def test_unaligned(dut, size, burst):
    """Test that unaligned read and writes are performed correctly"""
    def get_random_words(length, size, num_bits):
        r_bytes = getrandbits(num_bits).to_bytes(size * length, 'little')
        r_words = [r_bytes[i * size:(i + 1) * size] for i in range(length)]
        r_ints = [int.from_bytes(w, 'little') for w in r_words]
        return r_bytes, r_ints

    axim = AXI4Master(dut, AXI_PREFIX, dut.clk)
    _, data_width, ram_start, ram_stop = get_parameters(dut)
    size = size if size else data_width

    await setup_dut(dut)

    burst_length = randrange(2, 16 if burst is AXIBurst.FIXED else 256)

    if burst is AXIBurst.FIXED:
        address = randrange(ram_start, ram_stop, size)
    else:
        base = randrange(ram_start, ram_stop, 4096)
        offset = randrange(0, 4096 - (burst_length - 1) * size, size)
        address = base + offset

    unaligned_addr = address + randrange(1, size)
    shift = unaligned_addr % size

    # Write aligned, read unaligned
    write_bytes, write_values = \
        get_random_words(burst_length, size, size * burst_length * 8)

    await axim.write(address, write_values, burst=burst, size=size)
    read_values = await axim.read(unaligned_addr,
                                  burst_length,
                                  burst=burst,
                                  size=size)

    if burst is AXIBurst.FIXED:
        mask = 2**((size - shift) * 8) - 1
        expected_values = \
            [(write_values[-1] >> (shift * 8)) & mask] * burst_length
    else:
        expected_bytes = write_bytes[shift:]
        expected_words = [
            expected_bytes[i * size:(i + 1) * size]
            for i in range(burst_length)
        ]
        expected_values = [int.from_bytes(w, 'little') for w in expected_words]

    compare_read_values(expected_values, read_values, burst, burst_length,
                        unaligned_addr)

    # Write unaligned, read aligned
    write_bytes, write_values = \
        get_random_words(burst_length, size,
                         (size * burst_length - shift) * 8)

    first_word = randrange(0, 2**(size * 8))
    await axim.write(address, first_word, burst=burst, size=size)
    await axim.write(unaligned_addr, write_values, burst=burst, size=size)
    read_values = await axim.read(address,
                                  burst_length,
                                  burst=burst,
                                  size=size)

    mask_low = 2**(shift * 8) - 1
    mask_high = (2**((size - shift) * 8) - 1) << (shift * 8)

    if burst is AXIBurst.FIXED:
        last_val = \
            first_word & mask_low | (write_values[-1] << shift * 8) & mask_high
        expected_values = [last_val] * burst_length
    else:
        first_bytes = (first_word & mask_low).to_bytes(shift, 'little')
        expected_bytes = first_bytes + write_bytes
        expected_words = [
            expected_bytes[i * size:(i + 1) * size]
            for i in range(burst_length - 1)
        ]
        expected_values = [int.from_bytes(w, 'little') for w in expected_words]

    compare_read_values(expected_values, read_values, burst, burst_length,
                        unaligned_addr)