downscaler: add chopper module
This commit is contained in:
parent
ad974a07ef
commit
e464935119
|
@ -0,0 +1,135 @@
|
|||
from migen.fhdl.std import *
|
||||
from migen.genlib.fsm import *
|
||||
|
||||
class Chopper(Module):
|
||||
def __init__(self, N, frac_bits):
|
||||
self.init = Signal()
|
||||
self.ready = Signal()
|
||||
self.next = Signal()
|
||||
self.p = Signal(frac_bits)
|
||||
self.q = Signal(frac_bits)
|
||||
self.chopper = Signal(N)
|
||||
|
||||
###
|
||||
|
||||
# initialization counter
|
||||
ic = Signal(frac_bits)
|
||||
ic_overflow = Signal()
|
||||
ic_inc = Signal()
|
||||
self.sync += \
|
||||
If(self.init,
|
||||
ic.eq(0),
|
||||
ic_overflow.eq(1)
|
||||
).Elif(ic_inc,
|
||||
If(ic + self.p >= self.q,
|
||||
ic.eq(ic + self.p - self.q),
|
||||
ic_overflow.eq(1)
|
||||
).Else(
|
||||
ic.eq(ic + self.p),
|
||||
ic_overflow.eq(0)
|
||||
)
|
||||
)
|
||||
|
||||
# computed N*p mod q
|
||||
Np = Signal(frac_bits)
|
||||
load_np = Signal()
|
||||
self.sync += If(load_np, Np.eq(ic))
|
||||
|
||||
fsm = FSM()
|
||||
self.submodules += fsm
|
||||
fsm.act("IDLE",
|
||||
self.ready.eq(1),
|
||||
If(self.init, NextState(0))
|
||||
)
|
||||
|
||||
prev_acc_r = Signal(frac_bits)
|
||||
prev_acc = prev_acc_r
|
||||
for i in range(N):
|
||||
acc = Signal(frac_bits)
|
||||
|
||||
# pipeline stage 1: update accumulators
|
||||
load_init_acc = Signal()
|
||||
self.sync += \
|
||||
If(load_init_acc,
|
||||
acc.eq(ic)
|
||||
).Elif(self.next,
|
||||
If(acc + Np >= Cat(self.q, 0), # FIXME: workaround for imbecilic Verilog extension rules, needs to be put in Migen backend
|
||||
acc.eq(acc + Np - self.q),
|
||||
).Else(
|
||||
acc.eq(acc + Np)
|
||||
)
|
||||
)
|
||||
|
||||
# pipeline stage 2: detect overflows and generate chopper signal
|
||||
load_init_chopper = Signal()
|
||||
self.sync += \
|
||||
If(load_init_chopper,
|
||||
self.chopper[i].eq(ic_overflow)
|
||||
).Elif(self.next,
|
||||
self.chopper[i].eq(prev_acc >= acc)
|
||||
)
|
||||
if i == N-1:
|
||||
self.sync += \
|
||||
If(load_init_chopper,
|
||||
prev_acc_r.eq(ic)
|
||||
).Elif(self.next,
|
||||
prev_acc_r.eq(acc)
|
||||
)
|
||||
prev_acc = acc
|
||||
|
||||
# initialize stage 2
|
||||
fsm.act(i,
|
||||
load_init_chopper.eq(1),
|
||||
ic_inc.eq(1),
|
||||
NextState(i + 1)
|
||||
)
|
||||
# initialize stage 1
|
||||
fsm.act(N + i,
|
||||
load_init_acc.eq(1),
|
||||
ic_inc.eq(1),
|
||||
NextState(N + i + 1) if i < N-1 else NextState("IDLE")
|
||||
)
|
||||
# initialize Np
|
||||
fsm.act(N, load_np.eq(1))
|
||||
|
||||
def _count_ones(n):
|
||||
r = 0
|
||||
while n:
|
||||
if n & 1:
|
||||
r += 1
|
||||
n >>= 1
|
||||
return r
|
||||
|
||||
class _ChopperTB(Module):
|
||||
def __init__(self):
|
||||
self.submodules.dut = Chopper(4, 16)
|
||||
|
||||
def gen_simulation(self, s):
|
||||
from migen.sim.generic import Proxy
|
||||
dut = Proxy(s, self.dut)
|
||||
|
||||
dut.init = 1
|
||||
dut.p = 320
|
||||
dut.q = 681
|
||||
yield
|
||||
dut.init = 0
|
||||
yield
|
||||
while not dut.ready:
|
||||
print("waiting")
|
||||
yield
|
||||
print("done")
|
||||
|
||||
dut.next = 1
|
||||
yield
|
||||
ones = 0
|
||||
niter = 681
|
||||
for i in range(niter):
|
||||
print("{:04b}".format(dut.chopper))
|
||||
ones += _count_ones(dut.chopper)
|
||||
yield
|
||||
print("Ones: {} (expected: {})".format(ones, dut.p*niter*4//dut.q))
|
||||
|
||||
if __name__ == "__main__":
|
||||
from migen.sim.generic import Simulator
|
||||
with Simulator(_ChopperTB()) as s:
|
||||
s.run(1000)
|
Loading…
Reference in New Issue