diff --git a/gateware/test_i2c.py b/gateware/test_i2c.py index 1aaa43f..2013faa 100644 --- a/gateware/test_i2c.py +++ b/gateware/test_i2c.py @@ -1,5 +1,6 @@ from amaranth import * from i2c import * +from amlib.io.i2c import * from amaranth.lib.io import pin_layout from tests import BaseTestClass, provide_testcase_name @@ -45,33 +46,6 @@ class TestCSROperation(BaseTestClass): self.harness = TestHarness() - def _write_csr(self, bus, index, data): - yield bus.addr.eq(index) - yield bus.w_stb.eq(1) - yield bus.w_data.eq(data) - yield Tick() - yield bus.w_stb.eq(0) - yield Tick() - - - def _wait_for_signal(self, signal, polarity=False, require_edge=True, timeout=1000): - ready_for_edge = not require_edge # If we don't require edge, we can just ignore - - while True: - timeout -= 1 - if timeout == 0: - self.fail(f"_wait_for_signal({signal}, {polarity}, {require_edge}, {timeout}, timed out!") - - read = yield signal - if read == polarity: - if ready_for_edge: - break - else: - ready_for_edge = True - - yield Tick() - - # NOTE So ideally there are more test cases... but the initiator itself is well tested, # and we only really need it to work for a limited set of use cases, so exhaustive testing # isn't a huge deal. As well, we can cover all valid uses of the signals with one test. diff --git a/gateware/test_uart.py b/gateware/test_uart.py index 49ea6b3..59bed32 100644 --- a/gateware/test_uart.py +++ b/gateware/test_uart.py @@ -1,17 +1,57 @@ from amaranth import * from amaranth.sim import * +from amlib.io.serial import * from uart import * from tests import BaseTestClass, provide_testcase_name +__all__ = ["TestHarness", "TestUART"] + + class TestHarness(Elaboratable): def __init__(self): - self.uut = UART(10e6) + self.uut = UART(10e6, fifo_depth=16) + self.uart = AsyncSerial(divisor=int(10e6 // 115200), divisor_bits=16, data_bits=8, parity="none") def elaborate(self, platform): assert platform is None m = Module() + m.submodules.uut = self.uut + m.submodules.uart = self.uart - return m \ No newline at end of file + # Connect UART lines + m.d.comb += [ + self.uut.rx.eq(self.uart.tx.o), + self.uart.rx.i.eq(self.uut.tx), + ] + + # Connect the data lines so we are always pulling data out... for now + m.d.comb += [ + self.uart.rx.ack.eq(1), + ] + + return m + + +class TestUART(BaseTestClass): + def setUp(self): + self.harness = TestHarness() + + + @provide_testcase_name + def test_operation(self, test_name): + def test(): + for i in range(20): + yield from self._write_csr(self.harness.uut.bus, 2, i) + + for _ in range(2000): + yield Tick() + + yield from self._write_csr(self.harness.uut.bus, 0, 1000) + + for _ in range(20000): + yield Tick() + + self._run_test(test, test_name) diff --git a/gateware/tests.py b/gateware/tests.py index c60d4d8..7ef0bfc 100644 --- a/gateware/tests.py +++ b/gateware/tests.py @@ -37,6 +37,34 @@ class BaseTestClass(unittest.TestCase): del sim + ######### Random Utilities ######## + def _write_csr(self, bus, index, data): + yield bus.addr.eq(index) + yield bus.w_stb.eq(1) + yield bus.w_data.eq(data) + yield Tick() + yield bus.w_stb.eq(0) + yield Tick() + + + def _wait_for_signal(self, signal, polarity=False, require_edge=True, timeout=1000): + ready_for_edge = not require_edge # If we don't require edge, we can just ignore + + while True: + timeout -= 1 + if timeout == 0: + self.fail(f"_wait_for_signal({signal}, {polarity}, {require_edge}, {timeout}, timed out!") + + read = yield signal + if read == polarity: + if ready_for_edge: + break + else: + ready_for_edge = True + + yield Tick() + + def provide_testcase_name(fn): """Decorator that provides a function with access to its own class and name.""" def wrapper(self): diff --git a/gateware/uart.py b/gateware/uart.py index 3380eb7..0b52827 100644 --- a/gateware/uart.py +++ b/gateware/uart.py @@ -100,10 +100,10 @@ class UART(Elaboratable): # SR Hookups m.d.comb += [ - self.SR.r_data[0].eq(self._tx_fifo.level < self.fifo_depth), # txfifo_full - self.SR.r_data[1].eq(self._tx_fifo.level > 0), # txfifo_empty - self.SR.r_data[2].eq(self._rx_fifo.level < self.fifo_depth), # rxfifo_full - self.SR.r_data[3].eq(self._rx_fifo.level > 0), # rxfifo_empty + self.SR.r_data[0].eq(self._tx_fifo.level == self.fifo_depth), # txfifo_full + self.SR.r_data[1].eq(self._tx_fifo.level == 0), # txfifo_empty + self.SR.r_data[2].eq(self._rx_fifo.level == self.fifo_depth), # rxfifo_full + self.SR.r_data[3].eq(self._rx_fifo.level == 0), # rxfifo_empty ] # DR hookups