Skip to content

Commit e464935

Browse files
author
Sebastien Bourdeauducq
committedJan 21, 2014
downscaler: add chopper module
1 parent ad974a0 commit e464935

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
 

Diff for: ‎misoclib/videostream/downscaler.py

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
from migen.fhdl.std import *
2+
from migen.genlib.fsm import *
3+
4+
class Chopper(Module):
5+
def __init__(self, N, frac_bits):
6+
self.init = Signal()
7+
self.ready = Signal()
8+
self.next = Signal()
9+
self.p = Signal(frac_bits)
10+
self.q = Signal(frac_bits)
11+
self.chopper = Signal(N)
12+
13+
###
14+
15+
# initialization counter
16+
ic = Signal(frac_bits)
17+
ic_overflow = Signal()
18+
ic_inc = Signal()
19+
self.sync += \
20+
If(self.init,
21+
ic.eq(0),
22+
ic_overflow.eq(1)
23+
).Elif(ic_inc,
24+
If(ic + self.p >= self.q,
25+
ic.eq(ic + self.p - self.q),
26+
ic_overflow.eq(1)
27+
).Else(
28+
ic.eq(ic + self.p),
29+
ic_overflow.eq(0)
30+
)
31+
)
32+
33+
# computed N*p mod q
34+
Np = Signal(frac_bits)
35+
load_np = Signal()
36+
self.sync += If(load_np, Np.eq(ic))
37+
38+
fsm = FSM()
39+
self.submodules += fsm
40+
fsm.act("IDLE",
41+
self.ready.eq(1),
42+
If(self.init, NextState(0))
43+
)
44+
45+
prev_acc_r = Signal(frac_bits)
46+
prev_acc = prev_acc_r
47+
for i in range(N):
48+
acc = Signal(frac_bits)
49+
50+
# pipeline stage 1: update accumulators
51+
load_init_acc = Signal()
52+
self.sync += \
53+
If(load_init_acc,
54+
acc.eq(ic)
55+
).Elif(self.next,
56+
If(acc + Np >= Cat(self.q, 0), # FIXME: workaround for imbecilic Verilog extension rules, needs to be put in Migen backend
57+
acc.eq(acc + Np - self.q),
58+
).Else(
59+
acc.eq(acc + Np)
60+
)
61+
)
62+
63+
# pipeline stage 2: detect overflows and generate chopper signal
64+
load_init_chopper = Signal()
65+
self.sync += \
66+
If(load_init_chopper,
67+
self.chopper[i].eq(ic_overflow)
68+
).Elif(self.next,
69+
self.chopper[i].eq(prev_acc >= acc)
70+
)
71+
if i == N-1:
72+
self.sync += \
73+
If(load_init_chopper,
74+
prev_acc_r.eq(ic)
75+
).Elif(self.next,
76+
prev_acc_r.eq(acc)
77+
)
78+
prev_acc = acc
79+
80+
# initialize stage 2
81+
fsm.act(i,
82+
load_init_chopper.eq(1),
83+
ic_inc.eq(1),
84+
NextState(i + 1)
85+
)
86+
# initialize stage 1
87+
fsm.act(N + i,
88+
load_init_acc.eq(1),
89+
ic_inc.eq(1),
90+
NextState(N + i + 1) if i < N-1 else NextState("IDLE")
91+
)
92+
# initialize Np
93+
fsm.act(N, load_np.eq(1))
94+
95+
def _count_ones(n):
96+
r = 0
97+
while n:
98+
if n & 1:
99+
r += 1
100+
n >>= 1
101+
return r
102+
103+
class _ChopperTB(Module):
104+
def __init__(self):
105+
self.submodules.dut = Chopper(4, 16)
106+
107+
def gen_simulation(self, s):
108+
from migen.sim.generic import Proxy
109+
dut = Proxy(s, self.dut)
110+
111+
dut.init = 1
112+
dut.p = 320
113+
dut.q = 681
114+
yield
115+
dut.init = 0
116+
yield
117+
while not dut.ready:
118+
print("waiting")
119+
yield
120+
print("done")
121+
122+
dut.next = 1
123+
yield
124+
ones = 0
125+
niter = 681
126+
for i in range(niter):
127+
print("{:04b}".format(dut.chopper))
128+
ones += _count_ones(dut.chopper)
129+
yield
130+
print("Ones: {} (expected: {})".format(ones, dut.p*niter*4//dut.q))
131+
132+
if __name__ == "__main__":
133+
from migen.sim.generic import Simulator
134+
with Simulator(_ChopperTB()) as s:
135+
s.run(1000)

0 commit comments

Comments
 (0)
Please sign in to comment.