new-sonar/gateware/test_i2c.py
David Lenfesty ad3be1f4c7 gateware: put in some testing infrastructure
It's pretty hacky tbh, probably should be improved.

But also this will probably scale with the entire project so I don't
care.
2023-01-29 20:38:32 -07:00

91 lines
2.3 KiB
Python

from amaranth import *
from i2c import *
from amaranth.lib.io import pin_layout
from tests import BaseTestClass, provide_testcase_name
__all__ = ["i2c_layout", "I2CBusSimulator", "TestHarness", "TestCSROperation"]
class TestHarness(Elaboratable):
def __init__(self):
self.i2c = I2CBusSimulator()
self.uut = I2C(10_000_000, 100_000, self.i2c.create_interface())
self.i2c_target = I2CTarget(self.i2c.create_interface())
def elaborate(self, platform):
assert platform is None
m = Module()
m.submodules.i2c = self.i2c
m.submodules.uut = self.uut
m.submodules.i2c_target = self.i2c_target
m.d.comb += self.i2c_target.address.eq(0xAA >> 1)
return m
class TestCSROperation(BaseTestClass):
def setUp(self):
self.harness = TestHarness()
@provide_testcase_name
def test_send_byte(self, test_name):
def test():
yield Tick()
self._run_test(test, test_name)
i2c_layout = [
("sda", pin_layout(1, "io")),
("scl", pin_layout(1, "io")),
]
class I2CBusSimulator(Elaboratable):
def __init__(self):
self.interfaces = []
self.sda = Signal()
self.scl = Signal()
def elaborate(self, target):
assert target is None, "This bus simulator should never be used in real hardware!"
n = len(self.interfaces)
m = Module()
m.d.comb += self.sda.eq(1)
m.d.comb += self.scl.eq(1)
# TODO maybe output a bus contention signal?
# First interfaces get priority over interfaces added after
for i in reversed(range(n)):
# Emulate bus drivers
with m.If(self.interfaces[i].sda.oe):
m.d.comb += self.sda.eq(self.interfaces[i].sda.o)
with m.If(self.interfaces[i].scl.oe):
m.d.comb += self.scl.eq(self.interfaces[i].scl.o)
pass
# Connect inputs to bus value
m.d.comb += [
self.interfaces[i].sda.i.eq(self.sda),
self.interfaces[i].scl.i.eq(self.scl),
]
return m
def create_interface(self) -> Record:
new_interface = Record(i2c_layout)
self.interfaces.append(new_interface)
return new_interface