manta/test/test_io_core_hw.py

121 lines
4.0 KiB
Python

import os
from random import getrandbits
import pytest
from amaranth import *
from amaranth.lib import io
from amaranth_boards.icestick import ICEStickPlatform
from amaranth_boards.nexys4ddr import Nexys4DDRPlatform
from manta import *
from manta.utils import *
class IOCoreLoopbackTest(Elaboratable):
def __init__(self, platform, port):
self.platform = platform
self.port = port
def elaborate(self, platform):
# Since we know that all the tests will be called only after the FPGA
# is programmed, we can just push all the wiring into the elaborate
# method, instead of needing to define Manta in the __init__() method
probe0 = Signal()
probe1 = Signal(2)
probe2 = Signal(8)
probe3 = Signal(20)
probe4 = Signal(init=1)
probe5 = Signal(2, init=2)
probe6 = Signal(8)
probe7 = Signal(20, init=65538)
self.manta = manta = Manta()
manta.cores.io = IOCore(
inputs=[probe0, probe1, probe2, probe3],
outputs=[probe4, probe5, probe6, probe7],
)
manta.interface = UARTInterface(
port=self.port, baudrate=3e6, clock_freq=platform.default_clk_frequency
)
m = Module()
m.submodules.manta = manta
uart_pins = platform.request("uart", dir={"tx": "-", "rx": "-"})
m.submodules.uart_rx = uart_rx = io.Buffer("i", uart_pins.rx)
m.submodules.uart_tx = uart_tx = io.Buffer("o", uart_pins.tx)
m.d.comb += [
probe0.eq(probe4),
probe1.eq(probe5),
probe2.eq(probe6),
probe3.eq(probe7),
manta.interface.rx.eq(uart_rx.i),
uart_tx.o.eq(manta.interface.tx),
]
return m
def build_and_program(self):
self.platform.build(self, do_program=True)
def verify_output_probe_initial_values(self):
"""
Test that all output probes take their expected initial values.
We can't really test for the same of input probes, since the
strobe register pulses every time the get_probe() method is called.
"""
for p in self.manta.cores.io._outputs:
measured = self.manta.cores.io.get_probe(p)
if measured != p.init:
raise ValueError(
f"Output probe {p.name} took initial value of {measured} instead of {p.init}."
)
def verify_probes_update(self):
"""
This design ties all the output probes to input probes, so this
test sets the outputs to random values, and verifies the inputs match
"""
inputs = self.manta.cores.io._inputs
outputs = self.manta.cores.io._outputs
# The config is specified in such a way that the first output is
# connected to the first output, the second output is connected
# to the second input, and so on...
for i, o in zip(inputs, outputs):
value = getrandbits(len(i))
self.manta.cores.io.set_probe(o, value)
readback = self.manta.cores.io.get_probe(i)
if readback != value:
raise ValueError(
f"Reading {o.name} through {i.name} yielded {readback} instead of {value}!"
)
else:
print(
f"Reading {o.name} through {i.name} yielded {readback} as expected."
)
def verify(self):
self.build_and_program()
self.verify_output_probe_initial_values()
self.verify_probes_update()
@pytest.mark.skipif(not xilinx_tools_installed(), reason="no toolchain installed")
def test_output_probe_initial_values_xilinx():
port = os.environ["NEXYS4DDR_PORT"]
IOCoreLoopbackTest(Nexys4DDRPlatform(), port).verify()
@pytest.mark.skipif(not ice40_tools_installed(), reason="no toolchain installed")
def test_output_probe_initial_values_ice40():
port = os.environ["ICESTICK_PORT"]
IOCoreLoopbackTest(ICEStickPlatform(), port).verify()