artiq/artiq/gateware/grabber/core.py

178 lines
4.5 KiB
Python

from migen import *
from migen.genlib.cdc import MultiReg
from misoc.interconnect.csr import *
class FrequencyCounter(Module, AutoCSR):
def __init__(self, width=8):
self.freq_count = CSRStatus(width)
# # #
toggle = Signal(reset_less=True)
toggle_sys = Signal()
toggle.attr.add("no_retiming")
self.sync.cl += toggle.eq(~toggle)
self.specials += MultiReg(toggle, toggle_sys)
timer = Signal(width+1)
tick = Signal(reset=1)
count = Signal(width)
toggle_sys_r = Signal()
self.sync += [
Cat(timer, tick).eq(timer + 1),
toggle_sys_r.eq(toggle_sys),
If(tick,
self.freq_count.status.eq(count),
count.eq(0)
).Else(
If(toggle_sys & ~toggle_sys_r, count.eq(count + 1))
)
]
bitseq = [
# 0 1 2 3 4 5 6
6, 5, 4, 3, 2, 1, 27,
# 7 8 9 10 11 12 13
26, 0, 13, 12, 11, 10, 9,
# 14 15 16 17 18 19 20
25, 24, 8, 7, 20, 19, 18,
# 21 22 23
17, 23, 22
]
assert len(set(bitseq)) == 24
class Parser(Module, AutoCSR):
"""Parses 28 bit encoded words and track pixel coordinates."""
def __init__(self, width):
self.cl = cl = Signal(28)
self.last_x = CSRStatus(width)
self.last_y = CSRStatus(width)
self.pix = pix = Record([
("x", width),
("y", width),
("a", 8),
("b", 8),
("c", 8),
("stb", 1),
("eop", 1),
])
# # #
last_x = Signal(width)
last_y = Signal(width)
lval = Signal()
fval = Signal()
dval = Signal()
last_lval = Signal()
last_fval = Signal()
self.comb += [
Cat(dval, fval, lval).eq(cl[14:17]),
pix.stb.eq(dval & fval & lval),
pix.eop.eq(~fval & last_fval),
Cat(pix.a, pix.b, pix.c).eq(Cat(cl[i] for i in bitseq))
]
self.sync.cl += [
last_lval.eq(lval),
last_fval.eq(fval),
pix.x.eq(pix.x + 1),
If(~lval,
pix.x.eq(0),
If(last_lval, last_x.eq(pix.x)),
If(last_fval & last_lval,
pix.y.eq(pix.y + 1)
)
),
If(~fval,
If(last_fval, last_y.eq(pix.y)),
pix.y.eq(0)
)
]
last_x.attr.add("no_retiming")
last_y.attr.add("no_retiming")
self.specials += [
MultiReg(last_x, self.last_x.status),
MultiReg(last_y, self.last_y.status)
]
class ROI(Module):
"""ROI Engine. For each frame, accumulates pixels values within a
rectangular region of interest, and reports the total."""
@staticmethod
def count_len(width, shift):
# limit width to 31 to avoid problems with CPUs and RTIO inputs
return min(31, 2*width + 16 - shift)
def __init__(self, pix, shift):
count_len = ROI.count_len(len(pix.x), shift)
self.cfg = cfg = Record([
("x0", len(pix.x)),
("x1", len(pix.x)),
("y0", len(pix.y)),
("y1", len(pix.y)),
])
self.out = out = Record([
("update", 1),
# registered output - can be used as CDC input
("count", count_len),
])
# # #
# stage 1 - generate "good" (in-ROI) signals
y_good = Signal()
x_good = Signal()
stb = Signal()
eop = Signal()
gray = Signal(16)
self.sync.cl += [
If(pix.y == cfg.y0,
y_good.eq(1)
),
If(pix.y == cfg.y1,
y_good.eq(0)
),
If(pix.x == cfg.x0,
x_good.eq(1)
),
If(pix.x == cfg.x1,
x_good.eq(0)
),
If(pix.eop,
y_good.eq(0),
x_good.eq(0)
),
gray.eq(Cat(pix.a, pix.b)[shift:]),
stb.eq(pix.stb),
eop.eq(pix.eop)
]
# stage 2 - accumulate
count = Signal(count_len)
self.sync.cl += [
If(stb & x_good & y_good,
count.eq(count + gray),
),
out.update.eq(0),
If(eop,
count.eq(0),
out.update.eq(1),
out.count.eq(count)
)
]