mirror of https://github.com/m-labs/artiq.git
135 lines
3.8 KiB
Python
135 lines
3.8 KiB
Python
import unittest
|
|
|
|
from migen import *
|
|
from artiq.gateware.rtio.phy.edge_counter import *
|
|
|
|
CONFIG_COUNT_RISING = 0b0001
|
|
CONFIG_COUNT_FALLING = 0b0010
|
|
CONFIG_SEND_COUNT_EVENT = 0b0100
|
|
CONFIG_RESET_TO_ZERO = 0b1000
|
|
|
|
|
|
class TimeoutError(Exception):
|
|
pass
|
|
|
|
|
|
class Testbench:
|
|
def __init__(self, counter_width=32):
|
|
self.input = Signal()
|
|
self.dut = SimpleEdgeCounter(self.input, counter_width=counter_width)
|
|
|
|
self.fragment = self.dut.get_fragment()
|
|
cd = ClockDomain("rio")
|
|
self.fragment.clock_domains.append(cd)
|
|
self.rio_rst = cd.rst
|
|
|
|
def write_config(self, config):
|
|
bus = self.dut.rtlink.o
|
|
yield bus.data.eq(config)
|
|
yield bus.stb.eq(1)
|
|
yield
|
|
yield bus.stb.eq(0)
|
|
yield
|
|
|
|
def read_event(self, timeout):
|
|
bus = self.dut.rtlink.i
|
|
for _ in range(timeout):
|
|
if (yield bus.stb):
|
|
break
|
|
yield
|
|
else:
|
|
raise TimeoutError
|
|
return (yield bus.data)
|
|
|
|
def fetch_count(self, zero=False):
|
|
c = CONFIG_SEND_COUNT_EVENT
|
|
if zero:
|
|
c |= CONFIG_RESET_TO_ZERO
|
|
yield from self.write_config(c)
|
|
return (yield from self.read_event(1))
|
|
|
|
def toggle_input(self):
|
|
yield self.input.eq(1)
|
|
yield
|
|
yield self.input.eq(0)
|
|
yield
|
|
|
|
def reset_rio(self):
|
|
yield self.rio_rst.eq(1)
|
|
yield
|
|
yield self.rio_rst.eq(0)
|
|
yield
|
|
|
|
def run(self, gen):
|
|
run_simulation(self.fragment, gen,
|
|
clocks={n: 5 for n in ["sys", "rio", "rio_phy"]})
|
|
|
|
|
|
class TestEdgeCounter(unittest.TestCase):
|
|
def test_init(self):
|
|
tb = Testbench()
|
|
|
|
def gen():
|
|
# No counts initially...
|
|
self.assertEqual((yield from tb.fetch_count()), 0)
|
|
|
|
# ...nor any sensitivity.
|
|
yield from tb.toggle_input()
|
|
self.assertEqual((yield from tb.fetch_count()), 0)
|
|
|
|
tb.run(gen())
|
|
|
|
def test_sensitivity(self):
|
|
tb = Testbench()
|
|
|
|
def gen(sensitivity_config, expected_rising, expected_falling):
|
|
yield from tb.write_config(sensitivity_config)
|
|
yield tb.input.eq(1)
|
|
yield
|
|
self.assertEqual((yield from tb.fetch_count(zero=True)),
|
|
expected_rising)
|
|
|
|
yield from tb.write_config(sensitivity_config)
|
|
yield tb.input.eq(0)
|
|
yield
|
|
self.assertEqual((yield from tb.fetch_count()), expected_falling)
|
|
|
|
yield
|
|
with self.assertRaises(TimeoutError):
|
|
# Make sure there are no more suprious events.
|
|
yield from tb.read_event(10)
|
|
|
|
tb.run(gen(CONFIG_COUNT_RISING, 1, 0))
|
|
tb.run(gen(CONFIG_COUNT_FALLING, 0, 1))
|
|
tb.run(gen(CONFIG_COUNT_RISING | CONFIG_COUNT_FALLING, 1, 1))
|
|
|
|
def test_reset(self):
|
|
tb = Testbench()
|
|
|
|
def gen():
|
|
# Generate one count.
|
|
yield from tb.write_config(CONFIG_COUNT_RISING)
|
|
yield from tb.toggle_input()
|
|
self.assertEqual((yield from tb.fetch_count()), 1)
|
|
|
|
# Make sure it is gone after an RTIO reset, and the counter isn't
|
|
# sensitive anymore.
|
|
yield from tb.write_config(CONFIG_COUNT_RISING)
|
|
yield from tb.reset_rio()
|
|
yield from tb.toggle_input()
|
|
self.assertEqual((yield from tb.fetch_count()), 0)
|
|
|
|
tb.run(gen())
|
|
|
|
def test_saturation(self):
|
|
for width in range(3, 5):
|
|
tb = Testbench(counter_width=width)
|
|
|
|
def gen():
|
|
yield from tb.write_config(CONFIG_COUNT_RISING)
|
|
for _ in range(2**width + 1):
|
|
yield from tb.toggle_input()
|
|
self.assertEqual((yield from tb.fetch_count()), 2**width - 1)
|
|
|
|
tb.run(gen())
|