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:
parent
4a96be86c0
commit
baf9c07858
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue