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 ----------------------------------------------------------------------------------------
|
||||
|
||||
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):
|
||||
"""Timing monitor with pulse input/output
|
||||
|
||||
|
@ -214,20 +256,29 @@ class PulseTiming(Module):
|
|||
* countdown triggered by a low to high pulse on `trigger`
|
||||
* `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
|
||||
* 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):
|
||||
self.trigger = Signal()
|
||||
self.ready = Signal()
|
||||
self.ready_p = Signal()
|
||||
|
||||
ready_d = Signal()
|
||||
trigger_d = Signal()
|
||||
triggered = Signal()
|
||||
tctrl = tXXDController(t)
|
||||
self.submodules += tctrl
|
||||
timing = Timing(t)
|
||||
self.submodules += timing
|
||||
|
||||
self.sync += If(self.trigger, triggered.eq(1)),
|
||||
self.comb += [
|
||||
self.ready.eq(triggered & tctrl.ready),
|
||||
self.ready_p.eq(edge(self, self.ready)),
|
||||
tctrl.valid.eq(edge(self, self.trigger)),
|
||||
self.sync += [
|
||||
If(self.trigger, triggered.eq(1)),
|
||||
trigger_d.eq(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