From e464935119abf590157fd1770518c26e71c98921 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 21 Jan 2014 15:56:51 +0100 Subject: [PATCH] downscaler: add chopper module --- misoclib/videostream/downscaler.py | 135 +++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 misoclib/videostream/downscaler.py diff --git a/misoclib/videostream/downscaler.py b/misoclib/videostream/downscaler.py new file mode 100644 index 000000000..cda3b9bb5 --- /dev/null +++ b/misoclib/videostream/downscaler.py @@ -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)