phy/utils: improve ConstBitSlip:

* optional register=False to decrease latency by 1 cycle
* require explicit `cycles` as it influences latency (min_cycles
  still can be used)
* add unit tests
This commit is contained in:
Jędrzej Boczar 2021-06-01 12:46:21 +02:00
parent 4a96be86c0
commit baf9c07858
2 changed files with 69 additions and 5 deletions

View File

@ -44,11 +44,9 @@ def edge(mod, cond):
return ~cond_d & cond
class ConstBitSlip(Module):
def __init__(self, dw, slp, i=None, o=None, cycles=None):
def __init__(self, dw, slp, cycles, i=None, o=None, register=True):
self.i = Signal(dw, name='i') if i is None else i
self.o = Signal(dw, name='o') if o is None else o
if cycles is None:
cycles = self.min_cycles(slp, dw)
assert cycles >= 1, cycles
assert 0 <= slp <= cycles*dw-1, (slp, cycles, dw)
@ -57,7 +55,12 @@ class ConstBitSlip(Module):
# # #
self.r = r = Signal((cycles+1)*dw, reset_less=True)
self.sync += r.eq(Cat(r[dw:], self.i))
if register:
self.sync += r.eq(Cat(r[dw:], self.i))
else:
reg = Signal(cycles*dw, reset_less=True)
self.sync += reg.eq(Cat(reg[dw:], self.i))
self.comb += r.eq(Cat(reg, self.i))
self.comb += self.o.eq(r[slp+1:dw+slp+1])
@staticmethod

View File

@ -9,7 +9,7 @@ import itertools
from migen import *
from litedram.phy.utils import Serializer, Deserializer, Latency, chunks, bit
from litedram.phy.utils import Serializer, Deserializer, Latency, chunks, bit, ConstBitSlip
from test.phy_common import run_simulation
@ -186,3 +186,64 @@ class LatencyTests(unittest.TestCase):
with self.assertRaises(ValueError):
getattr(l, attr)
l.sys6x # ok
class TestConstBitslip(unittest.TestCase):
class Dut(Module):
def __init__(self, dw, **kwargs):
self.i = Signal(dw)
self.o = Signal(dw)
bs = ConstBitSlip(dw, **kwargs)
self.submodules += bs
self.comb += [
self.o.eq(bs.o),
bs.i.eq(self.i),
]
def test_register(self):
outputs = {
0: [0b0011, 0b0000],
1: [0b0110, 0b0000],
2: [0b1100, 0b0000],
3: [0b1000, 0b0001],
}
for slp, out in outputs.items():
with self.subTest(slp=slp):
def generator(dut):
yield dut.i.eq(0b0011)
yield
self.assertEqual((yield dut.o), 0)
yield dut.i.eq(0)
yield
self.assertEqual((yield dut.o), out[0])
yield
self.assertEqual((yield dut.o), out[1])
yield
self.assertEqual((yield dut.o), 0)
dut = self.Dut(dw=4, slp=slp, cycles=1)
run_simulation(dut, generator(dut))
def test_no_register(self):
outputs = {
0: [0b0011, 0b0000],
1: [0b0110, 0b0000],
2: [0b1100, 0b0000],
3: [0b1000, 0b0001],
}
for slp, out in outputs.items():
with self.subTest(slp=slp):
def generator(dut):
self.assertEqual((yield dut.o), 0)
yield dut.i.eq(0b0011)
yield
self.assertEqual((yield dut.o), out[0])
yield dut.i.eq(0)
yield
self.assertEqual((yield dut.o), out[1])
yield
self.assertEqual((yield dut.o), 0)
dut = self.Dut(dw=4, slp=slp, cycles=1, register=False)
run_simulation(dut, generator(dut))