def __init__(self): self.busy = Signal() self.sink = Sink(CMD_REC) self.source = Source([('d',8), ('last',1)]) sm = FSM(reset_state="IDLE") self.submodules += sm self.comb += [ self.source.stb.eq(0), self.source.payload.last.eq(0) ] ssum = Signal(8) token_next = Record(CMD_REC) token = Record(CMD_REC) self.comb += token_next.eq(token) self.sync += token.eq(token_next) sm.act("IDLE", If(self.sink.stb, self.sink.ack.eq(1), token_next.eq(self.sink.payload), NextState('c0'))) _outs = [ 0x55, Cat(token.a[8:14], 0, token.wr), token.a[0:8], token.d, ssum ] s = _outs[0] for i in _outs[1:-1]: s = s + i self.sync += ssum.eq(s) for c, v in enumerate(_outs): _last = 1 if c == len(_outs) - 1 else 0 _next = "IDLE" if _last else "c%d" % (c + 1) sm.act("c%d" % c, self.source.stb.eq(1), self.source.payload.d.eq(v), self.source.payload.last.eq(_last), If(self.source.ack, NextState(_next) ))
def __init__(self): self.busy = Signal() self.sink = Sink(CMD_REC) self.source = Source([('d',8), ('last',1)]) sm = FSM(reset_state="IDLE") self.submodules += sm self.comb += [ self.source.stb.eq(0), self.source.payload.last.eq(0) ] ssum = Signal(8) token_next = Record(CMD_REC) token = Record(CMD_REC) self.comb += token_next.eq(token) self.sync += token.eq(token_next) sm.act("IDLE", If(self.sink.stb, self.sink.ack.eq(1), token_next.eq(self.sink.payload), NextState('c0'))) _outs = [ 0x55, Cat(token.a[8:14], 0, token.wr), token.a[0:8], token.d, ssum ] s = _outs[0] for i in _outs[1:-1]: s = s + i self.sync += ssum.eq(s) for c, v in enumerate(_outs): _last = 1 if c == len(_outs) - 1 else 0 _next = "IDLE" if _last else "c%d" % (c + 1) sm.act("c%d" % c, self.source.stb.eq(1), self.source.payload.d.eq(v), self.source.payload.last.eq(_last), If(self.source.ack, NextState(_next) ))
class _InputManager(Module): def __init__(self, interface, counter, fifo_depth): data_width = rtlink.get_data_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if interface.timestamped: ev_layout.append(("timestamp", counter.width + fine_ts_width)) self.ev = Record(ev_layout) self.readable = Signal() self.re = Signal() self.overflow = Signal() # pulsed # # # fifo = ClockDomainsRenamer({"read": "rsys", "write": "rio"})( AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # FIFO write if data_width: self.comb += fifo_in.data.eq(interface.data) if interface.timestamped: if fine_ts_width: full_ts = Cat(interface.fine_ts, counter.value_rio) else: full_ts = counter.value_rio self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(interface.stb) # FIFO read self.comb += [ self.ev.eq(fifo_out), self.readable.eq(fifo.readable), fifo.re.eq(self.re) ] overflow_sync = PulseSynchronizer("rio", "rsys") overflow_ack_sync = PulseSynchronizer("rsys", "rio") self.submodules += overflow_sync, overflow_ack_sync overflow_blind = Signal() self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable & ~overflow_blind) self.sync.rio += [ If(fifo.we & ~fifo.writable, overflow_blind.eq(1)), If(overflow_ack_sync.o, overflow_blind.eq(0)) ] self.comb += [ overflow_ack_sync.i.eq(overflow_sync.o), self.overflow.eq(overflow_sync.o) ]
def __init__(self): self.sink = Sink(ULPI_DATA_D) self.source = Source(ULPI_DATA_D) self._ctl = CSRStorageEx(1) snapshot = self._ctl.re reset = self._ctl.storage[0] self._num_ovf = Perfcounter(snapshot, reset) self._num_total = Perfcounter(snapshot, reset) self.comb += If(self.sink.stb, self._num_total.inc()) self.comb += If(self.source.stb & ~self.source.ack, self._num_ovf.inc()) valid = Signal() data = Record(ULPI_DATA_D) self.comb += [If( self.sink.stb, self.sink.ack.eq(1), )] self.sync += [ If( self.sink.stb, valid.eq(1), If( valid & ~self.source.ack, data.rxcmd.eq(1), data.d.eq(RXCMD_MAGIC_OVF), ).Else(data.eq(self.sink.payload))).Elif( self.source.ack, valid.eq(0)) ] self.comb += [self.source.stb.eq(valid), self.source.payload.eq(data)]
def __init__(self): self.sink = Sink(ULPI_DATA_D) self.source = Source(ULPI_DATA_D) valid = Signal() data = Record(ULPI_DATA_D) self.comb += [ If(self.sink.stb, self.sink.ack.eq(1), )] self.sync += [ If(self.sink.stb, valid.eq(1), If(valid & ~self.source.ack, data.rxcmd.eq(1), data.d.eq(RXCMD_MAGIC_OVF), ).Else( data.eq(self.sink.payload) ) ).Elif(self.source.ack, valid.eq(0) )] self.comb += [ self.source.stb.eq(valid), self.source.payload.eq(data) ]
class DownscalerCore(Module): def __init__(self, base_layout, N, res_bits): self.init = Signal() self.ready = Signal() self.ce = Signal() self.hres_in = Signal(res_bits) self.vres_in = Signal(res_bits) self.i = Record([("w"+str(i), base_layout) for i in range(N)]) self.hres_out = Signal(res_bits) self.vres_out = Signal(res_bits) self.o = Record([("w"+str(i), base_layout) for i in range(N)]) self.stb = Signal() ### packbits = log2_int(N) hcounter = Signal(res_bits-packbits) self.sync += If(self.init, hcounter.eq(self.hres_in[packbits:] - 1) ).Elif(self.ce, If(hcounter == 0, hcounter.eq(self.hres_in[packbits:] - 1) ).Else( hcounter.eq(hcounter - 1) ) ) self.submodules.vselector = InsertReset(InsertCE(Chopper(res_bits))) self.comb += [ self.vselector.reset.eq(self.init), self.vselector.ce.eq(self.ce & (hcounter == 0)), self.vselector.p.eq(self.vres_out), self.vselector.q.eq(self.vres_in) ] self.submodules.hselector = MultiChopper(N, res_bits) self.comb += [ self.hselector.init.eq(self.init), self.ready.eq(self.hselector.ready), self.hselector.next.eq(self.ce), self.hselector.p.eq(self.hres_out), self.hselector.q.eq(self.hres_in) ] self.submodules.compacter = InsertReset(InsertCE(Compacter(base_layout, N))) self.submodules.packer = InsertReset(InsertCE(Packer(base_layout, N))) self.comb += [ self.compacter.reset.eq(self.init), self.packer.reset.eq(self.init), self.compacter.ce.eq(self.ce), self.packer.ce.eq(self.ce), self.compacter.i.eq(self.i), self.compacter.sel.eq(self.hselector.chopper & Replicate(self.vselector.chopper, N)), self.packer.i.eq(self.compacter.o), self.packer.count.eq(self.compacter.count), self.o.eq(self.packer.o), self.stb.eq(self.packer.stb) ]
class _InputManager(Module): def __init__(self, interface, counter, fifo_depth): data_width = rtlink.get_data_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if interface.timestamped: ev_layout.append(("timestamp", counter.width + fine_ts_width)) self.ev = Record(ev_layout) self.readable = Signal() self.re = Signal() self.overflow = Signal() # pulsed # # # fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), { "read": "rsys", "write": "rio" }) self.submodules += fifo # FIFO write if data_width: self.comb += fifo.din.data.eq(interface.data) if interface.timestamped: if fine_ts_width: full_ts = Cat(interface.fine_ts, counter.value_rio) else: full_ts = counter.value_rio self.comb += fifo.din.timestamp.eq(full_ts) self.comb += fifo.we.eq(interface.stb) # FIFO read self.comb += [ self.ev.eq(fifo.dout), self.readable.eq(fifo.readable), fifo.re.eq(self.re) ] overflow_sync = PulseSynchronizer("rio", "rsys") overflow_ack_sync = PulseSynchronizer("rsys", "rio") self.submodules += overflow_sync, overflow_ack_sync overflow_blind = Signal() self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable & ~overflow_blind) self.sync.rio += [ If(fifo.we & ~fifo.writable, overflow_blind.eq(1)), If(overflow_ack_sync.o, overflow_blind.eq(0)) ] self.comb += [ overflow_ack_sync.i.eq(overflow_sync.o), self.overflow.eq(overflow_sync.o) ]
def __init__(self, nimages, pack_factor, latency): epixel_layout = pixel_layout(pack_factor) sink_layout = [("i"+str(i), epixel_layout) for i in range(nimages)] self.sink = Sink(sink_layout) self.source = Source(epixel_layout) factors = [] for i in range(nimages): name = "f"+str(i) csr = CSRStorage(8, name=name) setattr(self, name, csr) factors.append(csr.storage) PipelinedActor.__init__(self, latency) ### sink_registered = Record(sink_layout) self.sync += If(self.pipe_ce, sink_registered.eq(self.sink.payload)) imgs = [getattr(sink_registered, "i"+str(i)) for i in range(nimages)] outval = Record(epixel_layout) for e in epixel_layout: name = e[0] inpixs = [getattr(img, name) for img in imgs] outpix = getattr(outval, name) for component in ["r", "g", "b"]: incomps = [getattr(pix, component) for pix in inpixs] outcomp = getattr(outpix, component) outcomp_full = Signal(19) self.comb += [ outcomp_full.eq(sum(incomp*factor for incomp, factor in zip(incomps, factors))), If(outcomp_full[18], outcomp.eq(2**10 - 1) # saturate on overflow ).Else( outcomp.eq(outcomp_full[8:18]) ) ] pipe_stmts = [] for i in range(latency-1): new_outval = Record(epixel_layout) pipe_stmts.append(new_outval.eq(outval)) outval = new_outval self.sync += If(self.pipe_ce, pipe_stmts) self.comb += self.source.payload.eq(outval)
class _InputManager(Module): def __init__(self, interface, counter, fifo_depth): data_width = rtlink.get_data_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if interface.timestamped: ev_layout.append(("timestamp", counter.width + fine_ts_width)) self.ev = Record(ev_layout) self.readable = Signal() self.re = Signal() self.overflow = Signal() # pulsed # # # fifo = ClockDomainsRenamer({ "read": "rsys", "write": "rio" })(AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # FIFO write if data_width: self.comb += fifo_in.data.eq(interface.data) if interface.timestamped: if fine_ts_width: full_ts = Cat(interface.fine_ts, counter.value_rtio) else: full_ts = counter.value_rtio self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(interface.stb) # FIFO read self.comb += [ self.ev.eq(fifo_out), self.readable.eq(fifo.readable), fifo.re.eq(self.re) ] overflow_transfer = _BlindTransfer() self.submodules += overflow_transfer self.comb += [ overflow_transfer.i.eq(fifo.we & ~fifo.writable), self.overflow.eq(overflow_transfer.o), ]
def __init__(self): self.busy=Signal() self.sink = Sink([('d',8)]) self.source = Source(CMD_REC) sm = FSM(reset_state="IDLE") self.submodules += sm # Basic checksum token = self.source.payload token_next = Record(CMD_REC) self.sync += token.eq(token_next) self.comb += token_next.eq(token) sm.act("IDLE", self.sink.ack.eq(1), If(self.sink.stb, If(self.sink.payload.d == 0x55, NextState("ADRH") ))) def parse_state(st, to, *update): sm.act(st, self.sink.ack.eq(1), If(self.sink.stb, NextState(to), *update )) parse_state('ADRH', 'ADRL', token_next.wr.eq(self.sink.payload.d[7]), token_next.a[8:14].eq(self.sink.payload.d[:6])) parse_state('ADRL', 'DATA', token_next.a[0:8].eq(self.sink.payload.d)), parse_state('DATA', 'CKSUM', token_next.d.eq(self.sink.payload.d)), sm.act("CKSUM", self.sink.ack.eq(1), If(self.sink.stb, NextState('ISSUE') ) ) sm.act("ISSUE", self.source.stb.eq(1), If(self.source.ack, NextState('IDLE')))
def __init__(self): self.busy=Signal() self.sink = Sink([('d',8)]) self.source = Source(CMD_REC) sm = FSM(reset_state="IDLE") self.submodules += sm # Basic checksum token = self.source.payload token_next = Record(CMD_REC) self.sync += token.eq(token_next) self.comb += token_next.eq(token) sm.act("IDLE", self.sink.ack.eq(1), If(self.sink.stb, If(self.sink.payload.d == 0x55, NextState("ADRH") ))) def parse_state(st, to, *update): sm.act(st, self.sink.ack.eq(1), If(self.sink.stb, NextState(to), *update )) parse_state('ADRH', 'ADRL', token_next.wr.eq(self.sink.payload.d[7]), token_next.a[8:14].eq(self.sink.payload.d[:6])) parse_state('ADRL', 'DATA', token_next.a[0:8].eq(self.sink.payload.d)), parse_state('DATA', 'CKSUM', token_next.d.eq(self.sink.payload.d)), sm.act("CKSUM", self.sink.ack.eq(1), If(self.sink.stb, NextState('ISSUE') ) ) sm.act("ISSUE", self.source.stb.eq(1), If(self.source.ack, NextState('IDLE')))
def __init__(self): self.sink = Sink(ULPI_DATA_D) self.source = Source(ULPI_DATA_D) self._ctl = CSRStorageEx(1) snapshot = self._ctl.re reset = self._ctl.storage[0] self._num_ovf = Perfcounter(snapshot, reset) self._num_total = Perfcounter(snapshot, reset) self.comb += If(self.sink.stb, self._num_total.inc()) self.comb += If(self.source.stb &~ self.source.ack, self._num_ovf.inc()) valid = Signal() data = Record(ULPI_DATA_D) self.comb += [ If(self.sink.stb, self.sink.ack.eq(1), )] self.sync += [ If(self.sink.stb, valid.eq(1), If(valid & ~self.source.ack, data.rxcmd.eq(1), data.d.eq(RXCMD_MAGIC_OVF), ).Else( data.eq(self.sink.payload) ) ).Elif(self.source.ack, valid.eq(0) )] self.comb += [ self.source.stb.eq(valid), self.source.payload.eq(data) ]
def __init__(self): self.sink = Sink(ULPI_DATA_D) self.source = Source(ULPI_DATA_D) valid = Signal() data = Record(ULPI_DATA_D) self.comb += [If( self.sink.stb, self.sink.ack.eq(1), )] self.sync += [ If( self.sink.stb, valid.eq(1), If( valid & ~self.source.ack, data.rxcmd.eq(1), data.d.eq(RXCMD_MAGIC_OVF), ).Else(data.eq(self.sink.payload))).Elif( self.source.ack, valid.eq(0)) ] self.comb += [self.source.stb.eq(valid), self.source.payload.eq(data)]
def __init__(self, pack_factor): hbits_dyn = _hbits - log2_int(pack_factor) timing_layout = [ ("hres", hbits_dyn), ("hsync_start", hbits_dyn), ("hsync_end", hbits_dyn), ("hscan", hbits_dyn), ("vres", _vbits), ("vsync_start", _vbits), ("vsync_end", _vbits), ("vscan", _vbits)] self.timing = Sink(timing_layout) self.pixels = Sink(pixel_layout(pack_factor)) self.phy = Source(phy_layout(pack_factor)) self.busy = Signal() ### hactive = Signal() vactive = Signal() active = Signal() hcounter = Signal(hbits_dyn) vcounter = Signal(_vbits) skip = bpc - bpc_phy self.comb += [ active.eq(hactive & vactive), If(active, [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:]) for p in ["p"+str(i) for i in range(pack_factor)] for c in ["y", "cb_cr"]], self.phy.de.eq(1) ), self.pixels.ack.eq(self.phy.ack & active) ] load_timing = Signal() tr = Record(timing_layout) self.sync += If(load_timing, tr.eq(self.timing.payload)) generate_en = Signal() generate_frame_done = Signal() self.sync += [ generate_frame_done.eq(0), If(generate_en, hcounter.eq(hcounter + 1), If(hcounter == 0, hactive.eq(1)), If(hcounter == tr.hres, hactive.eq(0)), If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)), If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)), If(hcounter == tr.hscan, hcounter.eq(0), If(vcounter == tr.vscan, vcounter.eq(0), generate_frame_done.eq(1) ).Else( vcounter.eq(vcounter + 1) ) ), If(vcounter == 0, vactive.eq(1)), If(vcounter == tr.vres, vactive.eq(0)), If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)), If(vcounter == tr.vsync_end, self.phy.vsync.eq(0)) ) ] self.submodules.fsm = FSM() self.fsm.act("GET_TIMING", self.timing.ack.eq(1), load_timing.eq(1), If(self.timing.stb, NextState("GENERATE")) ) self.fsm.act("GENERATE", self.busy.eq(1), If(~active | self.pixels.stb, self.phy.stb.eq(1), If(self.phy.ack, generate_en.eq(1)) ), If(generate_frame_done, NextState("GET_TIMING")) )
def __init__(self, pack_factor): hbits_dyn = _hbits - log2_int(pack_factor) timing_layout = [("hres", hbits_dyn), ("hsync_start", hbits_dyn), ("hsync_end", hbits_dyn), ("hscan", hbits_dyn), ("vres", _vbits), ("vsync_start", _vbits), ("vsync_end", _vbits), ("vscan", _vbits)] self.timing = Sink(timing_layout) self.pixels = Sink(pixel_layout(pack_factor)) self.phy = Source(phy_layout(pack_factor)) self.busy = Signal() ### hactive = Signal() vactive = Signal() active = Signal() hcounter = Signal(hbits_dyn) vcounter = Signal(_vbits) skip = bpc - bpc_phy self.comb += [ active.eq(hactive & vactive), If(active, [ getattr(getattr(self.phy.payload, p), c).eq( getattr(getattr(self.pixels.payload, p), c)[skip:]) for p in ["p" + str(i) for i in range(pack_factor)] for c in ["y", "cb_cr"] ], self.phy.de.eq(1)), self.pixels.ack.eq(self.phy.ack & active) ] load_timing = Signal() tr = Record(timing_layout) self.sync += If(load_timing, tr.eq(self.timing.payload)) generate_en = Signal() generate_frame_done = Signal() self.sync += [ generate_frame_done.eq(0), If( generate_en, hcounter.eq(hcounter + 1), If(hcounter == 0, hactive.eq(1)), If(hcounter == tr.hres, hactive.eq(0)), If(hcounter == tr.hsync_start, self.phy.hsync.eq(1)), If(hcounter == tr.hsync_end, self.phy.hsync.eq(0)), If( hcounter == tr.hscan, hcounter.eq(0), If(vcounter == tr.vscan, vcounter.eq(0), generate_frame_done.eq(1)).Else( vcounter.eq(vcounter + 1))), If(vcounter == 0, vactive.eq(1)), If(vcounter == tr.vres, vactive.eq(0)), If(vcounter == tr.vsync_start, self.phy.vsync.eq(1)), If(vcounter == tr.vsync_end, self.phy.vsync.eq(0))) ] self.submodules.fsm = FSM() self.fsm.act("GET_TIMING", self.timing.ack.eq(1), load_timing.eq(1), If(self.timing.stb, NextState("GENERATE"))) self.fsm.act( "GENERATE", self.busy.eq(1), If(~active | self.pixels.stb, self.phy.stb.eq(1), If(self.phy.ack, generate_en.eq(1))), If(generate_frame_done, NextState("GET_TIMING")))
def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles): self.sel = Signal(max=len(rbus)) # timestamp and value must be valid 1 cycle before we self.timestamp = Signal(counter.width + fine_ts_width) self.value = Signal(2) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 self.underflow = Signal() # valid 2 cycles after we self.underflow_reset = Signal() self.sequence_error = Signal() self.sequence_error_reset = Signal() # # # signal_underflow = Signal() signal_sequence_error = Signal() fifos = [] ev_layout = [("timestamp", counter.width + fine_ts_width), ("value", 2)] for n, chif in enumerate(rbus): # FIFO fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), { "write": "rsys", "read": "rio" }) self.submodules += fifo fifos.append(fifo) # Buffer buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() # Special cases replace = Signal() sequence_error = Signal() nop = Signal() self.sync.rsys += [ replace.eq(self.timestamp == buf.timestamp[fine_ts_width:]), sequence_error.eq( self.timestamp < buf.timestamp[fine_ts_width:]), nop.eq(self.value == buf.value) ] self.comb += If(self.we & (self.sel == n) & sequence_error, signal_sequence_error.eq(1)) # Buffer read and FIFO write self.comb += fifo.din.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.o_value_sys + guard_io_cycles) self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ If(buf_pending, If(in_guard_time, If(buf_just_written, signal_underflow.eq(1) ).Else( fifo.we.eq(1) ) ), If((self.we & (self.sel == n) & ~replace & ~nop & ~sequence_error), fifo.we.eq(1) ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), If(self.we & (self.sel == n) & ~nop & ~sequence_error, buf_just_written.eq(1), buf_pending.eq(1), buf.timestamp.eq(self.timestamp), buf.value.eq(self.value)) ] # Buffer output of FIFO to improve timing dout_stb = Signal() dout_ack = Signal() dout = Record(ev_layout) self.sync.rio += \ If(fifo.re, dout_stb.eq(1), dout.eq(fifo.dout) ).Elif(dout_ack, dout_stb.eq(0) ) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) # FIFO read through buffer self.comb += [ dout_ack.eq( dout.timestamp[fine_ts_width:] == counter.o_value_rio), chif.o_stb.eq(dout_stb & dout_ack), chif.o_value.eq(dout.value) ] if fine_ts_width: self.comb += chif.o_fine_ts.eq(dout.timestamp[:fine_ts_width]) self.comb += \ self.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel]) self.sync.rsys += [ If(self.underflow_reset, self.underflow.eq(0)), If(self.sequence_error_reset, self.sequence_error.eq(0)), If(signal_underflow, self.underflow.eq(1)), If(signal_sequence_error, self.sequence_error.eq(1)) ]
def __init__(self, interface, counter, fifo_depth, guard_io_cycles): data_width = rtlink.get_data_width(interface) address_width = rtlink.get_address_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if address_width: ev_layout.append(("address", address_width)) ev_layout.append(("timestamp", counter.width + fine_ts_width)) # ev must be valid 1 cycle before we to account for the latency in # generating replace, sequence_error and collision self.ev = Record(ev_layout) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 self.underflow = Signal() # valid 1 cycle after we, pulsed self.sequence_error = Signal() self.collision = Signal() self.busy = Signal() # pulsed # # # # FIFO fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})( AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # Buffer buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() # Special cases replace = Signal() sequence_error = Signal() collision = Signal() any_error = Signal() if interface.enable_replace: # Note: replace may be asserted at the same time as collision # when addresses are different. In that case, it is a collision. self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp) # Detect sequence errors on coarse timestamps only # so that they are mutually exclusive with collision errors. self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] < buf.timestamp[fine_ts_width:]) if interface.enable_replace: if address_width: different_addresses = self.ev.address != buf.address else: different_addresses = 0 if fine_ts_width: self.sync.rsys += collision.eq( (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]) |different_addresses)) else: self.sync.rsys += collision.eq( self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) self.comb += [ any_error.eq(sequence_error | collision), self.sequence_error.eq(self.we & sequence_error), self.collision.eq(self.we & collision) ] # Buffer read and FIFO write self.comb += fifo_in.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.value_sys + guard_io_cycles) self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ If(buf_pending, If(in_guard_time, If(buf_just_written, self.underflow.eq(1) ).Else( fifo.we.eq(1) ) ), If(self.we & ~replace & ~any_error, fifo.we.eq(1) ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), If(self.we & ~any_error, buf_just_written.eq(1), buf_pending.eq(1), buf.eq(self.ev) ) ] self.comb += self.writable.eq(fifo.writable) # Buffer output of FIFO to improve timing dout_stb = Signal() dout_ack = Signal() dout = Record(ev_layout) self.sync.rio += \ If(fifo.re, dout_stb.eq(1), dout.eq(fifo_out) ).Elif(dout_ack, dout_stb.eq(0) ) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) # FIFO read through buffer self.comb += [ dout_ack.eq( dout.timestamp[fine_ts_width:] == counter.value_rtio), interface.stb.eq(dout_stb & dout_ack) ] busy_transfer = _BlindTransfer() self.submodules += busy_transfer self.comb += [ busy_transfer.i.eq(interface.stb & interface.busy), self.busy.eq(busy_transfer.o), ] if data_width: self.comb += interface.data.eq(dout.data) if address_width: self.comb += interface.address.eq(dout.address) if fine_ts_width: self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
class _InputManager(Module): def __init__(self, interface, counter, fifo_depth): data_width = rtlink.get_data_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if interface.timestamped: ev_layout.append(("timestamp", counter.width + fine_ts_width)) self.ev = Record(ev_layout) self.readable = Signal() self.re = Signal() self.overflow = Signal() # pulsed # # # fifo = ClockDomainsRenamer({"read": "rsys", "write": "rio"})( AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # latency compensation if interface.delay: counter_rtio = Signal.like(counter.value_rtio, reset_less=True) self.sync.rtio += counter_rtio.eq(counter.value_rtio - (interface.delay + 1)) else: counter_rtio = counter.value_rtio # FIFO write if data_width: self.comb += fifo_in.data.eq(interface.data) if interface.timestamped: if fine_ts_width: full_ts = Cat(interface.fine_ts, counter_rtio) else: full_ts = counter_rtio self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(interface.stb) # FIFO read self.comb += [ self.ev.eq(fifo_out), self.readable.eq(fifo.readable), fifo.re.eq(self.re) ] overflow_transfer = BlindTransfer() self.submodules += overflow_transfer self.comb += [ overflow_transfer.i.eq(fifo.we & ~fifo.writable), self.overflow.eq(overflow_transfer.o), ]
def __init__(self, interface, counter, fifo_depth, guard_io_cycles): data_width = rtlink.get_data_width(interface) address_width = rtlink.get_address_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if address_width: ev_layout.append(("address", address_width)) ev_layout.append(("timestamp", counter.width + fine_ts_width)) # ev must be valid 1 cycle before we to account for the latency in # generating replace, sequence_error and nop self.ev = Record(ev_layout) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 self.underflow = Signal() # valid 1 cycle after we, pulsed self.sequence_error = Signal() self.collision_error = Signal() # # # # FIFO fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), { "write": "rsys", "read": "rio" }) self.submodules += fifo # Buffer buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() # Special cases replace = Signal() sequence_error = Signal() collision_error = Signal() any_error = Signal() nop = Signal() self.sync.rsys += [ # Note: replace does not perform any RTLink address checks, # i.e. a write to a different address will be silently replaced # as well. replace.eq(self.ev.timestamp == buf.timestamp), # Detect sequence errors on coarse timestamps only # so that they are mutually exclusive with collision errors. sequence_error.eq(self.ev.timestamp[fine_ts_width:] < buf.timestamp[fine_ts_width:]) ] if fine_ts_width: self.sync.rsys += collision_error.eq( (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) & (self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])) self.comb += any_error.eq(sequence_error | collision_error) if interface.suppress_nop: # disable NOP at reset: do not suppress a first write with all 0s nop_en = Signal(reset=0) self.sync.rsys += [ nop.eq(nop_en & optree("&", [ getattr(self.ev, a) == getattr(buf, a) for a in ("data", "address") if hasattr(self.ev, a) ], default=0)), # buf now contains valid data. enable NOP. If(self.we & ~any_error, nop_en.eq(1)), # underflows cancel the write. allow it to be retried. If(self.underflow, nop_en.eq(0)) ] self.comb += [ self.sequence_error.eq(self.we & sequence_error), self.collision_error.eq(self.we & collision_error) ] # Buffer read and FIFO write self.comb += fifo.din.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.value_sys + guard_io_cycles) self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ If(buf_pending, If(in_guard_time, If(buf_just_written, self.underflow.eq(1) ).Else( fifo.we.eq(1) ) ), If(self.we & ~replace & ~nop & ~any_error, fifo.we.eq(1) ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), If(self.we & ~nop & ~any_error, buf_just_written.eq(1), buf_pending.eq(1), buf.eq(self.ev)) ] self.comb += self.writable.eq(fifo.writable) # Buffer output of FIFO to improve timing dout_stb = Signal() dout_ack = Signal() dout = Record(ev_layout) self.sync.rio += \ If(fifo.re, dout_stb.eq(1), dout.eq(fifo.dout) ).Elif(dout_ack, dout_stb.eq(0) ) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) # FIFO read through buffer # TODO: report error on stb & busy self.comb += [ dout_ack.eq(dout.timestamp[fine_ts_width:] == counter.value_rio), interface.stb.eq(dout_stb & dout_ack) ] if data_width: self.comb += interface.data.eq(dout.data) if address_width: self.comb += interface.address.eq(dout.address) if fine_ts_width: self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
def __init__(self, interface, counter, fifo_depth, guard_io_cycles): data_width = rtlink.get_data_width(interface) address_width = rtlink.get_address_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if address_width: ev_layout.append(("address", address_width)) ev_layout.append(("timestamp", counter.width + fine_ts_width)) # ev must be valid 1 cycle before we to account for the latency in # generating replace, sequence_error and collision self.ev = Record(ev_layout) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 self.underflow = Signal() # valid 1 cycle after we, pulsed self.sequence_error = Signal() self.collision = Signal() self.busy = Signal() # pulsed # # # # FIFO fifo = ClockDomainsRenamer({ "write": "rsys", "read": "rio" })(AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # Buffer buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() # Special cases replace = Signal() sequence_error = Signal() collision = Signal() any_error = Signal() if interface.enable_replace: # Note: replace may be asserted at the same time as collision # when addresses are different. In that case, it is a collision. self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp) # Detect sequence errors on coarse timestamps only # so that they are mutually exclusive with collision errors. self.sync.rsys += sequence_error.eq( self.ev.timestamp[fine_ts_width:] < buf.timestamp[fine_ts_width:]) if interface.enable_replace: if address_width: different_addresses = self.ev.address != buf.address else: different_addresses = 0 if fine_ts_width: self.sync.rsys += collision.eq( (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]) | different_addresses)) else: self.sync.rsys += collision.eq(self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) self.comb += [ any_error.eq(sequence_error | collision), self.sequence_error.eq(self.we & sequence_error), self.collision.eq(self.we & collision) ] # Buffer read and FIFO write self.comb += fifo_in.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.value_sys + guard_io_cycles) self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ If(buf_pending, If(in_guard_time, If(buf_just_written, self.underflow.eq(1) ).Else( fifo.we.eq(1) ) ), If(self.we & ~replace & ~any_error, fifo.we.eq(1) ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), If(self.we & ~any_error, buf_just_written.eq(1), buf_pending.eq(1), buf.eq(self.ev)) ] self.comb += self.writable.eq(fifo.writable) # Buffer output of FIFO to improve timing dout_stb = Signal() dout_ack = Signal() dout = Record(ev_layout) self.sync.rio += \ If(fifo.re, dout_stb.eq(1), dout.eq(fifo_out) ).Elif(dout_ack, dout_stb.eq(0) ) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) # latency compensation if interface.delay: counter_rtio = Signal.like(counter.value_rtio) self.sync.rtio += counter_rtio.eq(counter.value_rtio - interface.delay + 1) else: counter_rtio = counter.value_rtio # FIFO read through buffer self.comb += [ dout_ack.eq(dout.timestamp[fine_ts_width:] == counter_rtio), interface.stb.eq(dout_stb & dout_ack) ] busy_transfer = BlindTransfer() self.submodules += busy_transfer self.comb += [ busy_transfer.i.eq(interface.stb & interface.busy), self.busy.eq(busy_transfer.o), ] if data_width: self.comb += interface.data.eq(dout.data) if address_width: self.comb += interface.address.eq(dout.address) if fine_ts_width: self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
def __init__(self, interface, counter, fifo_depth, guard_io_cycles): data_width = rtlink.get_data_width(interface) address_width = rtlink.get_address_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if address_width: ev_layout.append(("address", address_width)) ev_layout.append(("timestamp", counter.width + fine_ts_width)) # ev must be valid 1 cycle before we to account for the latency in # generating replace, sequence_error and nop self.ev = Record(ev_layout) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 self.underflow = Signal() # valid 1 cycle after we, pulsed self.sequence_error = Signal() self.collision_error = Signal() # # # # FIFO fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})( AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # Buffer buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() # Special cases replace = Signal() sequence_error = Signal() collision_error = Signal() any_error = Signal() nop = Signal() self.sync.rsys += [ # Note: replace does not perform any RTLink address checks, # i.e. a write to a different address will be silently replaced # as well. replace.eq(self.ev.timestamp == buf.timestamp), # Detect sequence errors on coarse timestamps only # so that they are mutually exclusive with collision errors. sequence_error.eq(self.ev.timestamp[fine_ts_width:] < buf.timestamp[fine_ts_width:]) ] if fine_ts_width: self.sync.rsys += collision_error.eq( (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) & (self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])) self.comb += any_error.eq(sequence_error | collision_error) if interface.suppress_nop: # disable NOP at reset: do not suppress a first write with all 0s nop_en = Signal(reset=0) addresses_equal = [getattr(self.ev, a) == getattr(buf, a) for a in ("data", "address") if hasattr(self.ev, a)] if addresses_equal: self.sync.rsys += nop.eq( nop_en & reduce(and_, addresses_equal)) else: self.comb.eq(nop.eq(0)) self.sync.rsys += [ # buf now contains valid data. enable NOP. If(self.we & ~any_error, nop_en.eq(1)), # underflows cancel the write. allow it to be retried. If(self.underflow, nop_en.eq(0)) ] self.comb += [ self.sequence_error.eq(self.we & sequence_error), self.collision_error.eq(self.we & collision_error) ] # Buffer read and FIFO write self.comb += fifo_in.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.value_sys + guard_io_cycles) self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ If(buf_pending, If(in_guard_time, If(buf_just_written, self.underflow.eq(1) ).Else( fifo.we.eq(1) ) ), If(self.we & ~replace & ~nop & ~any_error, fifo.we.eq(1) ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), If(self.we & ~nop & ~any_error, buf_just_written.eq(1), buf_pending.eq(1), buf.eq(self.ev) ) ] self.comb += self.writable.eq(fifo.writable) # Buffer output of FIFO to improve timing dout_stb = Signal() dout_ack = Signal() dout = Record(ev_layout) self.sync.rio += \ If(fifo.re, dout_stb.eq(1), dout.eq(fifo_out) ).Elif(dout_ack, dout_stb.eq(0) ) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) # FIFO read through buffer # TODO: report error on stb & busy self.comb += [ dout_ack.eq( dout.timestamp[fine_ts_width:] == counter.value_rio), interface.stb.eq(dout_stb & dout_ack) ] if data_width: self.comb += interface.data.eq(dout.data) if address_width: self.comb += interface.address.eq(dout.address) if fine_ts_width: self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])