fix test to work at 115200 baud
authorJacob Lifshay <programmerjake@gmail.com>
Tue, 26 Apr 2022 05:16:08 +0000 (22:16 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Tue, 26 Apr 2022 05:16:08 +0000 (22:16 -0700)
uart_demo.py

index 4054f9b0fcf96f3687335902d5cf2893863c6b85..76a8b0900a9c80c7a8307a242414f97ed2179f1c 100755 (executable)
@@ -10,6 +10,7 @@ from nmigen.sim import Tick
 from nmigen.build import ResourceError
 from nmutil.sim_util import do_sim
 import enum
+from fractions import Fraction
 
 
 def get_all_resources(platform, name):
@@ -100,8 +101,8 @@ class SimpleUART(Elaboratable):
 
 
 class UartDemo(Elaboratable):
-    def __init__(self, text, baud=115200):
-        self.simple_uart = SimpleUART(baud_rate=baud)
+    def __init__(self, text, baud_rate=115200):
+        self.simple_uart = SimpleUART(baud_rate=baud_rate)
         self.text = str(text)
         self.text_bytes = list(self.text.encode())
 
@@ -152,7 +153,7 @@ class TestUartDemo(unittest.TestCase):
             STOP = enum.auto()
 
         m = Module()
-        dut = UartDemo("test text", baud=9600)
+        dut = UartDemo("test text")
         sample_event = Signal()
         expected_state = Signal(ExpectedState)
         m.submodules.dut = dut
@@ -161,33 +162,53 @@ class TestUartDemo(unittest.TestCase):
             sample_event,
             expected_state,
         ]) as sim:
-            expected_bit_tick_count = round(
-                SIM_CLOCK_FREQ / dut.simple_uart.baud_rate)
+            current_tick = 0
+            bit_center_tick = Fraction(0)
+            ticks_per_bit = (Fraction(SIM_CLOCK_FREQ)
+                             / dut.simple_uart.baud_rate)
+
+            def tick():
+                nonlocal sim  # make debugging easier
+                nonlocal current_tick
+                current_tick += 1
+                yield Tick()
 
             def read_bit(is_initial=False):
+                nonlocal sim  # make debugging easier
+                nonlocal bit_center_tick, current_tick
                 yield sample_event.eq(1)
                 start_value = yield dut.simple_uart.tx
                 transition = None
-                for i in range(expected_bit_tick_count):
-                    yield Tick()
+                bit_center_tick += ticks_per_bit
+                while current_tick < bit_center_tick:
+                    yield from tick()
                     yield sample_event.eq(0)
                     value = yield dut.simple_uart.tx
                     if value != start_value:
-                        transition = i
+                        transition = current_tick
                         break
                 if transition is not None:
-                    delta = expected_bit_tick_count if is_initial else 1
-                    self.assertAlmostEqual(
-                        transition, expected_bit_tick_count / 2, delta=delta)
-                    for i in range(expected_bit_tick_count // 2):
-                        yield Tick()
+                    if not is_initial:
+                        expected = bit_center_tick - ticks_per_bit / 2
+                        # stop exceptions from causing synchronization loss
+                        with self.subTest():
+                            self.assertAlmostEqual(transition,
+                                                   expected,
+                                                   delta=1)
+                    bit_center_tick = current_tick + ticks_per_bit / 2
+                    while current_tick < bit_center_tick:
+                        yield from tick()
                         yield sample_event.eq(0)
                         value = yield dut.simple_uart.tx
-                        self.assertNotEqual(value, start_value,
-                                            "two transitions in one bit time")
+                        # stop exceptions from causing synchronization loss
+                        with self.subTest():
+                            self.assertNotEqual(
+                                value, start_value,
+                                "two transitions in one bit time")
                 return start_value
 
             def process():
+                nonlocal sim  # make debugging easier
                 yield expected_state.eq(ExpectedState.START)
                 start_bit = yield from read_bit(True)
                 for i in range(3):
@@ -218,10 +239,6 @@ class TestUartDemo(unittest.TestCase):
             sim.run()
 
 
-def build(platform, do_program):
-    platform.build(UartDemo("Hello World!\r\n"), do_program=do_program)
-
-
 PLATFORMS = {
     "ArtyA7_100": ArtyA7_100Platform,
     # TODO: add more