Skip to content

Commit

Permalink
update cic
Browse files Browse the repository at this point in the history
  • Loading branch information
jordens committed Aug 25, 2021
1 parent 81f607b commit ac8b72b
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 44 deletions.
51 changes: 26 additions & 25 deletions cic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# ([ ] possibly rate change/reset sequencing with output hold and settling)
# ([ ] possibly n-by-m channels (iter-by-parallel) and a single BRAM)


class CIC(Module):
def __init__(self, width=16, rate_width=9, order=3, channels=4):
"""
Expand All @@ -30,7 +31,7 @@ def __init__(self, width=16, rate_width=9, order=3, channels=4):
# rate change, rate ratio is `r_output/r_input = rate + 1`
self.rate = Signal(rate_width)
# output right shift to account for filter gain
# should be ceil(order*log2(rate))
# should be ceil(order*log2(rate + 1))
self.gain_shift = Signal(max=order*rate_width + 1)
# clear combs and integrators to establish new rate
self.rate_stb = Signal()
Expand All @@ -42,7 +43,7 @@ def __init__(self, width=16, rate_width=9, order=3, channels=4):
self.xi = Signal(max=channels)
# rate cycle complete
self.x_ack = Signal()

# output sample for given output channel
self.y = Signal((width, True), reset_less=True)
# output channel
Expand All @@ -51,30 +52,30 @@ def __init__(self, width=16, rate_width=9, order=3, channels=4):
self.y_stb = Signal()

###

channel = Signal(max=channels)
rate_cnt = Signal(rate_width)
stb = Signal(order)
rst = Signal(2*order + 1)
we = Signal(order)
rst = Signal(2*order)

self.sync += [
channel.eq(channel + 1),
stb[1:].eq(stb),
we[1:].eq(we),
rst[1:].eq(rst),
If(channel == channels - 1,
channel.eq(0),
rate_cnt.eq(rate_cnt - 1),
stb[0].eq(0),
we[0].eq(0),
If(rate_cnt == 0,
rate_cnt.eq(self.rate),
stb[0].eq(1),
we[0].eq(1),
rst[0].eq(0),
),
),
If(self.rate_stb,
channel.eq(0),
rate_cnt.eq(0),
stb[0].eq(1),
we[0].eq(1),
rst[0].eq(1),
)
]
Expand All @@ -83,37 +84,35 @@ def __init__(self, width=16, rate_width=9, order=3, channels=4):
comb = [width + n for n in range(order)]
integ = [width + order + (rate_width - 1)*(n + 1) for n in range(order)]

comb_r = [Signal((w, True), reset_less=True) for w in comb]
integ_r = [Signal((w, True), reset_less=True) for w in integ]
comb_r = [Signal((w, True)) for w in comb]
integ_r = [Signal((w, True)) for w in integ]
comb_w = [Signal((w, True), reset_less=True) for w in comb]
integ_w = [Signal((w, True), reset_less=True) for w in integ]

mem = Memory(sum(comb + integ), channels)
mem_r = mem.get_port()
mem_w = mem.get_port(write_capable=True, we_granularity=1)
self.specials += mem, mem_r, mem_w

# for the integrators for a given channel, read is 2 cycles ahead of write:

# for the integrators for a given channel, read is 2 cycles ahead of
# write:
# 0: read addr; 1: integ_r and old z, 2; new z and comb_w write-back
# for the combs there would only be one cycle:
# 0: read addr; 1: comb_r, old z, and comb_w write-back; 2: new z
# add one delay register at the read port to match the integrator
# read-write pointer spacing:
# 0: read addr; 1: mem dat_r; 2: comb_r, old z, and comb_w write-back; 3: new z
# alternatively try:
# 0: read addr; 1: comb_r, old z, and comb_w1; 3: new z and comb_w write-back
self.sync += [
Cat(comb_r).eq(mem_r.dat_r[:sum(comb)]),
]
# 0: read addr; 1: mem_dat_r; 2: comb_r, old z, and comb_w write-back; 3: new z
# or delay at the write port:
# 0: read addr; 1: comb_r, old z, and z1 store, 2: new z and comb_w write-back
self.comb += [
Cat(integ_r).eq(mem_r.dat_r[sum(comb):]),
Cat(comb_r, integ_r).eq(mem_r.dat_r),
mem_r.adr.eq(channel + 2),
mem_w.dat_w.eq(Cat(comb_w, integ_w)),
mem_w.adr.eq(channel),
mem_w.we.eq(Cat([Replicate(stb[n], w) for n, w in enumerate(comb)],
mem_w.we.eq(Cat([Replicate(we[n], w) for n, w in enumerate(comb)],
Replicate(1, sum(integ)))),
self.xi.eq(channel),
self.x_ack.eq(stb[0]),
self.x_ack.eq(we[0]),
self.yi.eq(channel - 2*order), # 2*order pipeline latency
self.y_stb.eq(1),
]
Expand All @@ -122,18 +121,20 @@ def __init__(self, width=16, rate_width=9, order=3, channels=4):
for i, (cr, cw) in enumerate(zip(comb_r, comb_w)):
self.comb += cw.eq(z)
z = Signal((len(cw) + 1, True), reset_less=True)
z0 = Signal((len(cr), True), reset_less=True)
self.sync += [
z.eq(cw - cr),
z0.eq(cr),
z.eq(cw - z0),
If(rst[i],
z.eq(0),
),
]
for i, (ir, iw) in enumerate(zip(integ_r, integ_w)):
self.sync += [
iw.eq(ir + z),
If(rst[order + 1 + i],
If(rst[order + i],
iw.eq(0),
),
]
z = iw
self.comb += self.y.eq(z >> self.gain_shift)
self.comb += self.y.eq(z >> self.gain_shift)
57 changes: 38 additions & 19 deletions fastino_phy.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,36 @@ def __init__(self, n_frame=14):
]


class Interpolator(Module):
def __init__(self, n_channels=32, n_bits=16):
self.rate = Signal(5, reset=16)
self.submodules.cic0 = CIC(width=n_bits, order=3,
rate_width=1 << len(self.rate) - 1, channels=n_channels//2)
self.submodules.cic1 = CIC(width=n_bits, order=3,
rate_width=1 << len(self.rate) - 1, channels=n_channels//2)
rate0 = Signal.like(self.rate)
self.sync += [
self.cic0.rate.eq(Array([(1 << i) - 1 for i in range(17)])[self.rate]),
self.cic0.gain_shift.eq(3*(self.rate + 1)),
If(self.rate != rate0,
self.cic0.rate_stb.eq(1),
),
]
self.comb += [
self.cic1.rate_stb.eq(self.cic0.rate_stb),
self.cic1.rate.eq(self.cic0.rate),
self.cic1.gain_shift.eq(self.cic0.gain_shift),
]
self.x = [Signal((n_bits, True)) for _ in range(n_channels)]
self.y = [Signal((n_bits, True)) for _ in range(n_channels)]
self.sync += [
self.cic0.x.eq(Array(self.x[:16])[self.cic0.xi]),
self.cic1.x.eq(Array(self.x[16:])[self.cic1.xi]),
Array(self.y[:16])[self.cic0.yi].eq(self.cic0.y),
Array(self.y[16:])[self.cic1.yi].eq(self.cic1.y),
]


class MultiSPI(Module):
"""Multi-bus SPI streamer"""
def __init__(self, platform, n_channels=32, n_bits=16):
Expand All @@ -332,18 +362,6 @@ def __init__(self, platform, n_channels=32, n_bits=16):
self.data = Signal(n)
self.stb = Signal()

spi_cic = ClockDomainsRenamer("spi")(CIC)
self.submodules.cic0 = spi_cic(order=3, rate_width=16, channels=16)
self.submodules.cic1 = spi_cic(order=3, rate_width=16, channels=16)
self.comb += [
self.cic0.rate.eq((1 << 16) - 1),
self.cic0.gain_shift.eq(3*16),
self.cic1.rate.eq(self.cic0.rate),
self.cic1.gain_shift.eq(self.cic0.gain_shift),
]
data_a = [Signal((n_bits, True)) for _ in range(32)]
data_b = [Signal((n_bits, True)) for _ in range(32)]

spi = [platform.request("dac", i) for i in range(32)]

self.busy = Signal()
Expand All @@ -362,16 +380,11 @@ def __init__(self, platform, n_channels=32, n_bits=16):
enable.eq(0),
self.busy.eq(0),
),
self.cic0.x.eq(Array(data_a[:16])[self.cic0.xi]),
self.cic1.x.eq(Array(data_a[16:])[self.cic1.xi]),
Array(data_b[:16])[self.cic0.yi].eq(self.cic0.y),
Array(data_b[16:])[self.cic1.yi].eq(self.cic1.y),
If(self.busy,
i.eq(i + 1),
).Elif(self.stb,
self.busy.eq(1),
Cat(enable, data_a).eq(self.data),
Cat(sr).eq(Cat(data_b)),
Cat(enable, sr).eq(self.data),
),
enable0.eq(enable),
]
Expand Down Expand Up @@ -550,6 +563,8 @@ def __init__(self, platform):
AsyncResetSynchronizer(cd_spi, ~locked),
]

self.submodules.int = ClockDomainsRenamer("spi")(Interpolator)()

self.submodules.spi = MultiSPI(platform)

assert len(cfg) + len(adr) + len(self.spi.data) == len(self.frame.body)
Expand All @@ -558,7 +573,11 @@ def __init__(self, platform):
# max data delay sys-spi < min sys-spi clock delay over all alignments
self.comb += [
self.spi.stb.eq(self.frame.stb),
self.spi.data.eq(self.frame.body[-len(self.spi.data):])
#self.spi.data.eq(self.frame.body[-len(self.spi.data):])
Cat(self.int.x).eq(self.frame.body[-len(Cat(self.int.x)):]),
Cat(self.spi.data).eq(Cat(
self.frame.body[-len(self.spi.data):][:32], self.int.y)),
self.int.rate.eq(cfg.reserved),
]

self.comb += [
Expand Down

0 comments on commit ac8b72b

Please sign in to comment.