phy/sim_utils: support low wait times (0/1) in PulseTiming

This commit is contained in:
Jędrzej Boczar 2021-07-02 16:09:37 +02:00 committed by Alessandro Comodi
parent f9a11ea5ce
commit 914d018cf8
2 changed files with 146 additions and 8 deletions

View File

@ -206,6 +206,48 @@ def log_level_getter(log_level):
# Simulator ---------------------------------------------------------------------------------------- # Simulator ----------------------------------------------------------------------------------------
class Timing(Module):
# slight modification of tXXDController
def __init__(self, t):
self.valid = Signal()
self.ready = Signal()
if t is None:
t = 0
if isinstance(t, Signal):
count = Signal.like(t)
else:
count = Signal(max=max(t, 2))
ready = Signal()
ready_reg = Signal()
self.comb += [
self.ready.eq(ready_reg | ready),
ready.eq((t == 0) & self.valid),
]
self.sync += \
If(self.valid,
If(t == 0,
ready_reg.eq(1)
).Else(
count.eq(t - 1),
If(t == 1,
ready_reg.eq(1)
).Else(
ready_reg.eq(0)
)
),
).Elif(~ready,
If(count > 1,
count.eq(count - 1),
),
If(count == 1,
ready_reg.eq(1)
)
)
class PulseTiming(Module): class PulseTiming(Module):
"""Timing monitor with pulse input/output """Timing monitor with pulse input/output
@ -214,20 +256,29 @@ class PulseTiming(Module):
* countdown triggered by a low to high pulse on `trigger` * countdown triggered by a low to high pulse on `trigger`
* `ready` is initially low, only after a trigger it can become high * `ready` is initially low, only after a trigger it can become high
* provides `ready_p` which is high only for 1 cycle when `ready` becomes high * provides `ready_p` which is high only for 1 cycle when `ready` becomes high
* supports t values starting from 0, with t=0 `ready_p` will pulse in the same
cycle in which `trigger` is high
""" """
def __init__(self, t): def __init__(self, t):
self.trigger = Signal() self.trigger = Signal()
self.ready = Signal() self.ready = Signal()
self.ready_p = Signal() self.ready_p = Signal()
ready_d = Signal() trigger_d = Signal()
triggered = Signal() triggered = Signal()
tctrl = tXXDController(t) timing = Timing(t)
self.submodules += tctrl self.submodules += timing
self.sync += If(self.trigger, triggered.eq(1)), self.sync += [
self.comb += [ If(self.trigger, triggered.eq(1)),
self.ready.eq(triggered & tctrl.ready), trigger_d.eq(self.trigger),
self.ready_p.eq(edge(self, self.ready)), ]
tctrl.valid.eq(edge(self, self.trigger)), self.comb += [
self.ready.eq((triggered & timing.ready) | ((t == 0) & self.trigger)),
self.ready_p.eq(reduce(or_, [
edge(self, self.ready),
(t == 0) & edge(self, self.trigger),
(t == 1) & edge(self, trigger_d),
])),
timing.valid.eq(edge(self, self.trigger)),
] ]

87
test/test_sim_utils.py Normal file
View File

@ -0,0 +1,87 @@
# This file is part of LiteDRAM.
#
# Copyright (c) 2021 Antmicro <www.antmicro.com>
# SPDX-License-Identifier: BSD-2-Clause
import unittest
from migen import *
from litedram.phy.sim_utils import PulseTiming
class TestSimUtils(unittest.TestCase):
def pulse_timing_test(self, dut, *, trigger, ready, ready_p, generators=None):
generators = generators or []
assert len(trigger) == len(ready) == len(ready_p)
ready_hist = ""
ready_p_hist = ""
def generator():
nonlocal ready_hist, ready_p_hist
for i in range(len(trigger)):
yield dut.trigger.eq(int(trigger[i]))
yield
ready_hist += str((yield dut.ready))
ready_p_hist += str((yield dut.ready_p))
run_simulation(dut, [generator(), *generators])
self.assertEqual(ready_hist, ready)
self.assertEqual(ready_p_hist, ready_p)
def test_pulse_timing_basic(self):
self.pulse_timing_test(PulseTiming(4),
trigger = "01000000",
ready = "00000111",
ready_p = "00000100",
)
def test_pulse_timing_1(self):
self.pulse_timing_test(PulseTiming(1),
trigger = "01000000",
ready = "00111111",
ready_p = "00100000",
)
def test_pulse_timing_0(self):
self.pulse_timing_test(PulseTiming(0),
trigger = "01000000",
ready = "01111111",
ready_p = "01000000",
)
def pulse_timing_signal_test(self, t, **kwargs):
class Dut(PulseTiming):
def __init__(self):
self.t = Signal(3)
super().__init__(self.t)
dut = Dut()
def generator():
yield
yield dut.t.eq(t)
yield
self.pulse_timing_test(dut, generators=[generator()], **kwargs)
def test_pulse_timing_signal(self):
self.pulse_timing_signal_test(
t = 4,
trigger = "00100000000000000",
ready = "00000011111111111",
ready_p = "00000010000000000",
)
def test_pulse_timing_signal_1(self):
self.pulse_timing_signal_test(
t = 1,
trigger = "00100000000000000",
ready = "00011111111111111",
ready_p = "00010000000000000",
)
def test_pulse_timing_signal_0(self):
self.pulse_timing_signal_test(
t = 0,
trigger = "00100000000000000",
ready = "00111111111111111",
ready_p = "00100000000000000",
)