phy/sim_utils: support low wait times (0/1) in PulseTiming
This commit is contained in:
parent
f9a11ea5ce
commit
914d018cf8
|
@ -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)),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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",
|
||||||
|
)
|
Loading…
Reference in New Issue