156 lines
4.9 KiB
Python
156 lines
4.9 KiB
Python
|
|
from amaranth.sim import Simulator
|
||
|
|
from manta.io_core import IOCore
|
||
|
|
from manta.utils import *
|
||
|
|
from random import randint
|
||
|
|
|
||
|
|
config = {
|
||
|
|
"type": "io",
|
||
|
|
"inputs": {"probe0": 1, "probe1": 2, "probe2": 8, "probe3": 20},
|
||
|
|
"outputs": {
|
||
|
|
"probe4": {"width": 1, "initial_value": 1},
|
||
|
|
"probe5": {"width": 2, "initial_value": 2},
|
||
|
|
"probe6": 8,
|
||
|
|
"probe7": {"width": 20, "initial_value": 65538},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
io_core = IOCore(config, base_addr=0, interface=None)
|
||
|
|
|
||
|
|
|
||
|
|
def pulse_strobe_register():
|
||
|
|
strobe_addr = io_core.mmap["strobe"]["addrs"][0]
|
||
|
|
yield from write_register(io_core, strobe_addr, 0)
|
||
|
|
yield from write_register(io_core, strobe_addr, 1)
|
||
|
|
yield from write_register(io_core, strobe_addr, 0)
|
||
|
|
|
||
|
|
|
||
|
|
def test_output_probe_initial_values():
|
||
|
|
def testbench():
|
||
|
|
# Verify all output probes initialize to the values in the config
|
||
|
|
for name, attrs in config["outputs"].items():
|
||
|
|
initial_value = 0
|
||
|
|
if isinstance(attrs, dict):
|
||
|
|
if "initial_value" in attrs:
|
||
|
|
initial_value = attrs["initial_value"]
|
||
|
|
|
||
|
|
output_probe = getattr(io_core, name)
|
||
|
|
value = yield output_probe
|
||
|
|
|
||
|
|
if value != initial_value:
|
||
|
|
raise ValueError(
|
||
|
|
f"Output probe {name} initialized to {value} instead of {initial_value}"
|
||
|
|
)
|
||
|
|
|
||
|
|
else:
|
||
|
|
print(f"Output probe {name} initialized to {value} as expected.")
|
||
|
|
|
||
|
|
simulate(io_core, testbench)
|
||
|
|
|
||
|
|
|
||
|
|
def test_input_probe_buffer_initial_value():
|
||
|
|
def testbench():
|
||
|
|
# Verify all input probe buffers initialize to zero
|
||
|
|
for name, width in config["inputs"].items():
|
||
|
|
addrs = io_core.mmap[name + "_buf"]["addrs"]
|
||
|
|
|
||
|
|
for addr in addrs:
|
||
|
|
yield from verify_register(io_core, addr, 0)
|
||
|
|
|
||
|
|
simulate(io_core, testbench)
|
||
|
|
|
||
|
|
|
||
|
|
def test_output_probe_buffer_initial_value():
|
||
|
|
def testbench():
|
||
|
|
# Verify all output probe buffers initialize to the values in the config
|
||
|
|
for name, attrs in config["outputs"].items():
|
||
|
|
addrs = io_core.mmap[name + "_buf"]["addrs"]
|
||
|
|
|
||
|
|
datas = [0] * len(addrs)
|
||
|
|
if isinstance(attrs, dict):
|
||
|
|
if "initial_value" in attrs:
|
||
|
|
datas = value_to_words(attrs["initial_value"], len(addrs))
|
||
|
|
|
||
|
|
for addr, data in zip(addrs, datas):
|
||
|
|
yield from verify_register(io_core, addr, data)
|
||
|
|
|
||
|
|
simulate(io_core, testbench)
|
||
|
|
|
||
|
|
|
||
|
|
def test_output_probes_are_writeable():
|
||
|
|
def testbench():
|
||
|
|
for name, attrs in config["outputs"].items():
|
||
|
|
if isinstance(attrs, dict):
|
||
|
|
width = attrs["width"]
|
||
|
|
else:
|
||
|
|
width = attrs
|
||
|
|
|
||
|
|
addrs = io_core.mmap[name + "_buf"]["addrs"]
|
||
|
|
test_value = randint(0, (2**width) - 1)
|
||
|
|
datas = value_to_words(test_value, len(addrs))
|
||
|
|
|
||
|
|
# write value to registers
|
||
|
|
for addr, data in zip(addrs, datas):
|
||
|
|
yield from write_register(io_core, addr, data)
|
||
|
|
|
||
|
|
# read value back from registers
|
||
|
|
for addr, data in zip(addrs, datas):
|
||
|
|
yield from verify_register(io_core, addr, data)
|
||
|
|
|
||
|
|
simulate(io_core, testbench)
|
||
|
|
|
||
|
|
|
||
|
|
def test_output_probes_update():
|
||
|
|
def testbench():
|
||
|
|
for name, attrs in config["outputs"].items():
|
||
|
|
if isinstance(attrs, dict):
|
||
|
|
width = attrs["width"]
|
||
|
|
else:
|
||
|
|
width = attrs
|
||
|
|
|
||
|
|
addrs = io_core.mmap[name + "_buf"]["addrs"]
|
||
|
|
test_value = randint(0, (2**width) - 1)
|
||
|
|
datas = value_to_words(test_value, len(addrs))
|
||
|
|
|
||
|
|
# write value to registers
|
||
|
|
for addr, data in zip(addrs, datas):
|
||
|
|
yield from write_register(io_core, addr, data)
|
||
|
|
|
||
|
|
# pulse strobe register
|
||
|
|
yield from pulse_strobe_register()
|
||
|
|
|
||
|
|
# check that outputs took updated value
|
||
|
|
output_probe = getattr(io_core, name)
|
||
|
|
value = yield (output_probe)
|
||
|
|
|
||
|
|
if value != test_value:
|
||
|
|
raise ValueError(
|
||
|
|
f"Output probe {name} took value {value} instead of {test_value} after pulsing strobe."
|
||
|
|
)
|
||
|
|
|
||
|
|
else:
|
||
|
|
print(f"Output probe {name} took value {value} after pulsing strobe.")
|
||
|
|
|
||
|
|
simulate(io_core, testbench)
|
||
|
|
|
||
|
|
|
||
|
|
def test_input_probes_update():
|
||
|
|
def testbench():
|
||
|
|
for name, width in config["inputs"].items():
|
||
|
|
test_value = randint(0, (2**width) - 1)
|
||
|
|
|
||
|
|
# set input probe value
|
||
|
|
input_probe = getattr(io_core, name)
|
||
|
|
yield input_probe.eq(test_value)
|
||
|
|
|
||
|
|
# pulse strobe register
|
||
|
|
yield from pulse_strobe_register()
|
||
|
|
|
||
|
|
# check that values are as expected once read back
|
||
|
|
addrs = io_core.mmap[name + "_buf"]["addrs"]
|
||
|
|
datas = value_to_words(test_value, len(addrs))
|
||
|
|
|
||
|
|
for addr, data in zip(addrs, datas):
|
||
|
|
yield from verify_register(io_core, addr, data)
|
||
|
|
|
||
|
|
simulate(io_core, testbench)
|