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, 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, nchan=3, depth=8): self.valid_i = Signal() self.chan_synced = Signal() self._r_channels_synced = CSRStatus() lst_control = [] all_control = Signal() for i in range(nchan): name = "data_in" + str(i) data_in = Record(channel_layout, name=name) setattr(self, name, data_in) name = "data_out" + str(i) data_out = Record(channel_layout, name=name) setattr(self, name, data_out) ### syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix") self.submodules += syncbuffer self.comb += [syncbuffer.din.eq(data_in.raw_bits()), data_out.raw_bits().eq(syncbuffer.dout)] is_control = Signal() self.comb += [is_control.eq(~data_out.de), syncbuffer.re.eq(~is_control | all_control)] lst_control.append(is_control) some_control = Signal() self.comb += [all_control.eq(optree("&", lst_control)), some_control.eq(optree("|", lst_control))] self.sync.pix += If(~self.valid_i, self.chan_synced.eq(0)).Else( If(some_control, If(all_control, self.chan_synced.eq(1)).Else(self.chan_synced.eq(0))) ) self.specials += MultiReg(self.chan_synced, self._r_channels_synced.status)
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, 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, port, lasmim_dma_wr, lasmim_dma_rd): self.submodules.writer = LiteUSBDMAWriter(lasmim_dma_wr) self.submodules.reader = LiteUSBDMAReader(lasmim_dma_rd, port.tag) self.submodules.ev = SharedIRQ(self.writer.ev, self.reader.ev) self.comb += [ Record.connect(port.source, self.writer.sink), Record.connect(self.reader.source, port.sink), ]
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): 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([('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, stream_slicer): self.source = stream.Endpoint(record_layout) self.end_marker_found = Signal() self.flush = Signal() hdrlen = (layout_len(record_layout) - 512)//8 record_raw = Record(record_layout) self.comb += [ record_raw.raw_bits().eq(stream_slicer.source), self.source.channel.eq(record_raw.channel), self.source.timestamp.eq(record_raw.timestamp), self.source.address.eq(record_raw.address), Case(record_raw.length, {hdrlen+i: self.source.data.eq(record_raw.data[:i*8]) for i in range(1, 512//8+1)}), ] fsm = FSM(reset_state="FLOWING") self.submodules += fsm fsm.act("FLOWING", If(stream_slicer.source_stb, If(record_raw.length == 0, NextState("END_MARKER_FOUND") ).Else( self.source.stb.eq(1) ) ), If(self.source.ack, stream_slicer.source_consume.eq(record_raw.length) ) ) fsm.act("END_MARKER_FOUND", self.end_marker_found.eq(1), If(self.flush, stream_slicer.flush.eq(1), NextState("WAIT_FLUSH") ) ) fsm.act("WAIT_FLUSH", If(stream_slicer.flush_done, NextState("SEND_EOP") ) ) fsm.act("SEND_EOP", self.source.eop.eq(1), self.source.stb.eq(1), If(self.source.ack, NextState("FLOWING")) )
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) ]
def request(self, name, number=None): resource = _lookup(self.available, name, number) rt, ri = _resource_type(resource) if number is None: resource_name = name else: resource_name = name + str(number) if isinstance(rt, int): obj = Signal(rt, name_override=resource_name) else: obj = Record(rt, name=resource_name) for name, inverted in ri: if inverted: getattr(obj, name).inverted = True for element in resource[2:]: if isinstance(element, Inverted): if isinstance(obj, Signal): obj.inverted = True if isinstance(element, PlatformInfo): obj.platform_info = element.info break self.available.remove(resource) self.matched.append((resource, obj)) return obj
def getPort(self): r = Record( sdramHostIf(flen(self.downstream.d_read), flen(self.downstream.i_addr))) self.ports.append(r) return r
def __init__(self): self.submodules.master = wishbone.Initiator(self.gen_reads()) self.pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)]) self.submodules.slave = SpiFlash(self.pads) self.submodules.tap = wishbone.Tap(self.slave.bus) self.submodules.intercon = wishbone.InterconnectPointToPoint( self.master.bus, self.slave.bus) self.cycle = 0
def __init__(self, width_or_layout, depth): self.we = Signal() self.writable = Signal() # not full self.re = Signal() self.readable = Signal() # not empty if isinstance(width_or_layout, list): self.din = Record(width_or_layout) self.dout = Record(width_or_layout) self.din_bits = self.din.raw_bits() self.dout_bits = self.dout.raw_bits() self.width = layout_len(width_or_layout) else: self.din = Signal(width_or_layout) self.dout = Signal(width_or_layout) self.din_bits = self.din self.dout_bits = self.dout self.width = width_or_layout
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, 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)
def __init__(self, **kwargs): self.ctrl_pads = Record(self.ctrl_layout) self.ctrl_pads.board.reset = 0b1111 # board-inverted self.ctrl_pads.frame.reset = 0b111 # pullup on cs_n self.ctrl_pads.trigger.reset = 1 self.submodules.dut = ResetInserter(["sys"])(PdqBase( self.ctrl_pads, **kwargs)) # self.comb += self.dut.reset_sys.eq(self.dut.comm.rg.reset) self.outputs = [] self.aux = []
def __init__(self, phy, tx_fifo_depth=16, rx_fifo_depth=16, phy_cd="sys"): self._rxtx = CSR(8) self._txfull = CSRStatus() self._rxempty = CSRStatus() self.submodules.ev = EventManager() self.ev.tx = EventSourceProcess() self.ev.rx = EventSourceProcess() self.ev.finalize() # # # # TX tx_fifo = _get_uart_fifo(tx_fifo_depth, source_cd=phy_cd) self.submodules += tx_fifo self.comb += [ tx_fifo.sink.stb.eq(self._rxtx.re), tx_fifo.sink.data.eq(self._rxtx.r), self._txfull.status.eq(~tx_fifo.sink.ack), Record.connect(tx_fifo.source, phy.sink), # Generate TX IRQ when tx_fifo becomes non-full self.ev.tx.trigger.eq(~tx_fifo.sink.ack) ] # RX rx_fifo = _get_uart_fifo(rx_fifo_depth, sink_cd=phy_cd) self.submodules += rx_fifo self.comb += [ Record.connect(phy.source, rx_fifo.sink), self._rxempty.status.eq(~rx_fifo.source.stb), self._rxtx.w.eq(rx_fifo.source.data), rx_fifo.source.ack.eq(self.ev.rx.clear), # Generate RX IRQ when tx_fifo becomes non-empty self.ev.rx.trigger.eq(~rx_fifo.source.stb) ]
def test_fast_serial_tx(): def feed_in(dut, pads, txns): for data, port in txns: yield dut.sink.payload.data.eq(data) yield dut.sink.payload.port.eq(port) yield dut.sink.stb.eq(1) yield while not (yield dut.sink.ack): yield yield dut.sink.stb.eq(0) def test_out(dut, pads, txns): for data, port in txns: while not (not (yield pads.di) and (yield pads.cts)): yield rx_data = 0 for i in range(8): yield rx_data |= (yield pads.di) << i yield rx_port = (yield pads.di) yield assert rx_data == data assert rx_port == port def drive_cts(dut, pads): yield pads.cts.eq(0) for i in range(5): yield yield pads.cts.eq(1) txns = [ (0b01010101, 0), (0x00, 1), ] pads = Record([ ("di", 1), ("clk", 1), ("di", 1), ("cts", 1), ]) dut = FastSerialTX(pads) run_simulation(dut, [ feed_in(dut, pads, txns), test_out(dut, pads, txns), drive_cts(dut, pads), ], vcd_name="serial_tx.vcd")
def create_rbus(fine_ts_bits, pads, output_only_pads): rbus = [] for pad in pads: layout = [("o_stb", 1), ("o_value", 2)] if fine_ts_bits: layout.append(("o_fine_ts", fine_ts_bits)) if pad not in output_only_pads: layout += [("oe", 1), ("i_stb", 1), ("i_value", 1), ("i_pileup", 1)] if fine_ts_bits: layout.append(("i_fine_ts", fine_ts_bits)) rbus.append(Record(layout)) return rbus
def __init__(self): # in pix clock domain self.valid_i = Signal() self.vsync = Signal() self.de = Signal() self.r = Signal(8) self.g = Signal(8) self.b = Signal(8) # in sys clock domain self.frame = Source(frame_layout) self.busy = Signal() ### fifo_stb = Signal() fifo_in = Record(frame_layout) self.comb += [ fifo_stb.eq(self.valid_i & self.de), fifo_in.r.eq(self.r), fifo_in.g.eq(self.g), fifo_in.b.eq(self.b), ] vsync_r = Signal() self.sync.pix += [ If(self.vsync & ~vsync_r, fifo_in.parity.eq(~fifo_in.parity)), vsync_r.eq(self.vsync) ] fifo = AsyncFIFO(layout_len(frame_layout), 256) self.add_submodule(fifo, {"write": "pix", "read": "sys"}) self.comb += [ fifo.we.eq(fifo_stb), fifo.din.eq(fifo_in.raw_bits()), self.frame.stb.eq(fifo.readable), self.frame.payload.raw_bits().eq(fifo.dout), fifo.re.eq(self.frame.ack), self.busy.eq(0) ]
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, phy, tx_fifo_depth=16, rx_fifo_depth=16): self._rxtx = CSR(8) self._txfull = CSRStatus() self._rxempty = CSRStatus() self.submodules.ev = EventManager() self.ev.tx = EventSourceProcess() self.ev.rx = EventSourceProcess() self.ev.finalize() # # # tx_fifo = SyncFIFO([("data", 8)], tx_fifo_depth) self.submodules += tx_fifo self.comb += [ tx_fifo.sink.stb.eq(self._rxtx.re), tx_fifo.sink.data.eq(self._rxtx.r), self._txfull.status.eq(~tx_fifo.sink.ack), Record.connect(tx_fifo.source, phy.sink) ] rx_fifo = SyncFIFO([("data", 8)], rx_fifo_depth) self.submodules += rx_fifo self.comb += [ Record.connect(phy.source, rx_fifo.sink), self._rxempty.status.eq(~rx_fifo.source.stb), self._rxtx.w.eq(rx_fifo.source.data), rx_fifo.source.ack.eq(self.ev.rx.clear) ] self.comb += [ # Generate TX IRQ when tx_fifo becomes empty self.ev.tx.trigger.eq(tx_fifo.source.stb), # Generate RX IRQ when rx_fifo becomes non-empty self.ev.rx.trigger.eq(~rx_fifo.source.stb), ]
def request(self, name, number=None): resource = _lookup(self.available, name, number) rt = _resource_type(resource) if isinstance(rt, int): obj = Signal(rt, name_override=resource[0]) else: obj = Record(rt, name=resource[0]) for element in resource[2:]: if isinstance(element, PlatformInfo): obj.platform_info = element.info break self.available.remove(resource) self.matched.append((resource, obj)) return obj
def __init__(self): self.valid_i = Signal() self.data_in0 = Record(channel_layout) self.data_in1 = Record(channel_layout) self.data_in2 = Record(channel_layout) self.valid_o = Signal() self.de = Signal() self.hsync = Signal() self.vsync = Signal() self.r = Signal(8) self.g = Signal(8) self.b = Signal(8) ### de = self.data_in0.de de_r = Signal() c = self.data_in0.c c_polarity = Signal(2) c_out = Signal(2) self.comb += [ self.de.eq(de_r), self.hsync.eq(c_out[0]), self.vsync.eq(c_out[1]) ] self.sync.pix += [ self.valid_o.eq(self.valid_i), self.r.eq(self.data_in2.d), self.g.eq(self.data_in1.d), self.b.eq(self.data_in0.d), de_r.eq(de), If(de_r & ~de, c_polarity.eq(c), c_out.eq(0)).Else(c_out.eq(c ^ c_polarity)) ]
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): self.valid_i = Signal() self.input = Signal(10) self.valid_o = Signal() self.output = Record(channel_layout) ### self.sync.pix += self.output.de.eq(1) for i, t in enumerate(control_tokens): self.sync.pix += If(self.input == t, self.output.de.eq(0), self.output.c.eq(i)) self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9]) for i in range(1, 8): self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i - 1] ^ ~self.input[8]) self.sync.pix += self.valid_o.eq(self.valid_i)
def __init__(self, mem, skip_ft245r=True): self.ctrl_pads = Record(self.ctrl_layout) self.ctrl_pads.adr.reset = 0b1111 self.ctrl_pads.trigger.reset = 1 self.ctrl_pads.frame.reset = 0b000 self.submodules.dut = ResetInserter(["sys"])(Pdq2Base(self.ctrl_pads)) self.comb += self.dut.reset_sys.eq(self.dut.comm.ctrl.reset) if skip_ft245r: reader = SimReader(mem) else: reader = SimFt245r_rx(mem) self.submodules.reader = ResetInserter(["sys"])(reader) self.comb += self.reader.reset_sys.eq(self.dut.comm.ctrl.reset) self.comb += self.dut.comm.sink.connect(self.reader.source) # override high-ack during reset draining the reader self.comb += self.reader.source.ack.eq(self.dut.comm.sink.ack & ~self.dut.comm.ctrl.reset) self.outputs = []
def __init__(self, nchan=3, depth=8): self.valid_i = Signal() self.chan_synced = Signal() self._channels_synced = CSRStatus() lst_control = [] all_control = Signal() for i in range(nchan): name = "data_in" + str(i) data_in = Record(channel_layout, name=name) setattr(self, name, data_in) name = "data_out" + str(i) data_out = Record(channel_layout, name=name) setattr(self, name, data_out) # # # syncbuffer = _SyncBuffer(layout_len(channel_layout), depth) syncbuffer = ClockDomainsRenamer("pix")(syncbuffer) self.submodules += syncbuffer self.comb += [ syncbuffer.din.eq(data_in.raw_bits()), data_out.raw_bits().eq(syncbuffer.dout) ] is_control = Signal() self.comb += [ is_control.eq(~data_out.de), syncbuffer.re.eq(~is_control | all_control) ] lst_control.append(is_control) some_control = Signal() self.comb += [ all_control.eq(reduce(and_, lst_control)), some_control.eq(reduce(or_, lst_control)) ] self.sync.pix += \ If(~self.valid_i, self.chan_synced.eq(0) ).Else( If(some_control, If(all_control, self.chan_synced.eq(1) ).Else( self.chan_synced.eq(0) ) ) ) self.specials += MultiReg(self.chan_synced, self._channels_synced.status)
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])
def UARTPads(): return Record([("tx", 1), ("rx", 1)])
def __init__(self, tsc, channels, mode, quash_channels=[], interface=None): if interface is None: interface = cri.Interface() self.cri = interface # # # if mode == "sync": fifo_factory = SyncFIFOBuffered sync_io = self.sync sync_cri = self.sync elif mode == "async": fifo_factory = lambda *args: ClockDomainsRenamer({"write": "rio", "read": "rsys"})(AsyncFIFO(*args)) sync_io = self.sync.rio sync_cri = self.sync.rsys else: raise ValueError i_statuses, i_datas, i_timestamps = [], [], [] i_ack = Signal() sel = self.cri.chan_sel[:16] for n, channel in enumerate(channels): iif = channel.interface.i if iif is None or n in quash_channels: i_datas.append(0) i_timestamps.append(0) i_statuses.append(0) continue # FIFO layout = get_channel_layout(len(tsc.coarse_ts), iif) fifo = fifo_factory(layout_len(layout), channel.ififo_depth) self.submodules += fifo fifo_in = Record(layout) fifo_out = Record(layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # FIFO write if iif.delay: counter_rtio = Signal.like(tsc.coarse_ts, reset_less=True) sync_io += counter_rtio.eq(tsc.coarse_ts - (iif.delay + 1)) else: counter_rtio = tsc.coarse_ts if hasattr(fifo_in, "data"): self.comb += fifo_in.data.eq(iif.data) if hasattr(fifo_in, "timestamp"): if hasattr(iif, "fine_ts"): full_ts = Cat(iif.fine_ts, counter_rtio) else: full_ts = counter_rtio self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(iif.stb) overflow_io = Signal() self.comb += overflow_io.eq(fifo.we & ~fifo.writable) if mode == "sync": overflow_trigger = overflow_io elif mode == "async": overflow_transfer = BlindTransfer() self.submodules += overflow_transfer self.comb += overflow_transfer.i.eq(overflow_io) overflow_trigger = overflow_transfer.o else: raise ValueError # FIFO read, CRI connection if hasattr(fifo_out, "data"): i_datas.append(fifo_out.data) else: i_datas.append(0) if hasattr(fifo_out, "timestamp"): ts_shift = 64 - len(fifo_out.timestamp) i_timestamps.append(fifo_out.timestamp << ts_shift) else: i_timestamps.append(0) selected = Signal() self.comb += selected.eq(sel == n) overflow = Signal() sync_cri += [ If(selected & i_ack, overflow.eq(0)), If(overflow_trigger, overflow.eq(1)) ] self.comb += fifo.re.eq(selected & i_ack & ~overflow) i_statuses.append(Cat(fifo.readable & ~overflow, overflow)) i_status_raw = Signal(2) self.comb += i_status_raw.eq(Array(i_statuses)[sel]) input_timeout = Signal.like(self.cri.i_timeout, reset_less=True) input_pending = Signal() self.cri.i_data.reset_less = True self.cri.i_timestamp.reset_less = True sync_cri += [ i_ack.eq(0), If(i_ack, self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), self.cri.i_data.eq(Array(i_datas)[sel]), self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), ), If((tsc.full_ts_cri >= input_timeout) | (i_status_raw != 0), If(input_pending, i_ack.eq(1)), input_pending.eq(0) ), If(self.cri.cmd == cri.commands["read"], input_timeout.eq(self.cri.i_timeout), input_pending.eq(1), self.cri.i_status.eq(0b100) ) ]
def __init__(self, word_width, fifo_depth): # in pix clock domain self.valid_i = Signal() self.vsync = Signal() self.de = Signal() self.r = Signal(8) self.g = Signal(8) self.b = Signal(8) self.counter = Signal(20) # Since math.log(1024*768, 2) = 19.58 word_layout = [("sof", 1), ("pixels", word_width)] self.frame = Source(word_layout) self.busy = Signal() self._overflow = CSR() self._start_counter = CSRStorage(1, reset=0) self.sync += [ If((self._start_counter.storage), self.counter.eq(self.counter + 1) ) ] de_r = Signal() self.sync.pix += de_r.eq(self.de) #initially self.sync.pix rgb2ycbcr = RGB2YCbCr() self.submodules += RenameClockDomains(rgb2ycbcr, "pix") #initially pix chroma_downsampler = YCbCr444to422() self.submodules += RenameClockDomains(chroma_downsampler, "pix") #initially pix self.comb += [ rgb2ycbcr.sink.stb.eq(self.valid_i), rgb2ycbcr.sink.sop.eq(self.de & ~de_r), rgb2ycbcr.sink.r.eq(self.r), rgb2ycbcr.sink.g.eq(self.g), rgb2ycbcr.sink.b.eq(self.b), Record.connect(rgb2ycbcr.source, chroma_downsampler.sink), chroma_downsampler.source.ack.eq(1) ] # XXX need clean up de = self.de vsync = self.vsync for i in range(rgb2ycbcr.latency + chroma_downsampler.latency): next_de = Signal() next_vsync = Signal() # Beware below...initially was self.sync.pix self.sync.pix += [ next_de.eq(de), next_vsync.eq(vsync) ] de = next_de vsync = next_vsync ################################################################################### # start of frame detection '''new_frame = Signal() self.comb += new_frame.eq(self.counter == 0)''' vsync_r = Signal() new_frame = Signal() self.comb += new_frame.eq(vsync & ~vsync_r) #self.sync.pix += vsync_r.eq(vsync) self.sync.pix += vsync_r.eq(vsync) # pack pixels into words cur_word = Signal(word_width) cur_word_valid = Signal() encoded_pixel = Signal(16) self.comb += encoded_pixel.eq(Cat(chroma_downsampler.source.y, chroma_downsampler.source.cb_cr)), pack_factor = word_width//16 assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2 pack_counter = Signal(max=pack_factor) #self.sync.pix += [ self.sync.pix += [ cur_word_valid.eq(0), If(new_frame, cur_word_valid.eq(pack_counter == (pack_factor - 1)), pack_counter.eq(0), ).Elif(chroma_downsampler.source.stb & de, [If(pack_counter == (pack_factor-i-1), cur_word[16*i:16*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)], cur_word_valid.eq(pack_counter == (pack_factor - 1)), pack_counter.eq(pack_counter + 1) ) ] # FIFO #Async for another clock domain, sync for our sys clock domain! F**k!! :( fifo = RenameClockDomains(AsyncFIFO(word_layout, fifo_depth), {"write": "pix", "read": "sys"}) self.submodules += fifo self.comb += [ fifo.din.pixels.eq(cur_word), fifo.we.eq(cur_word_valid) ] self.sync.pix += \ If(new_frame, fifo.din.sof.eq(1) ).Elif(cur_word_valid, fifo.din.sof.eq(0) ) self.comb += [ self.frame.stb.eq(fifo.readable), self.frame.payload.eq(fifo.dout), fifo.re.eq(self.frame.ack), self.busy.eq(0) ] # overflow detection pix_overflow = Signal() pix_overflow_reset = Signal() self.sync.pix += [ If(fifo.we & ~fifo.writable, pix_overflow.eq(1) ).Elif(pix_overflow_reset, pix_overflow.eq(0) ) ] sys_overflow = Signal() self.specials += MultiReg(pix_overflow, sys_overflow) self.comb += [ pix_overflow_reset.eq(self._overflow.re), ] overflow_mask = Signal() self.comb += [ self._overflow.w.eq(sys_overflow & ~overflow_mask), ] self.sync += \ If(self._overflow.re, overflow_mask.eq(1) ).Elif(pix_overflow_reset, overflow_mask.eq(0) )
def __init__(self, word_width, fifo_depth): # in pix clock domain self.valid_i = Signal() self.vsync = Signal() self.de = Signal() self.r = Signal(8) self.g = Signal(8) self.b = Signal(8) # in sys clock domain word_layout = [("sof", 1), ("pixels", word_width)] self.frame = Source(word_layout) self.busy = Signal() self._overflow = CSR() ### de_r = Signal() self.sync.pix += de_r.eq(self.de) rgb2ycbcr = RGB2YCbCr() self.submodules += RenameClockDomains(rgb2ycbcr, "pix") chroma_downsampler = YCbCr444to422() self.submodules += RenameClockDomains(chroma_downsampler, "pix") self.comb += [ rgb2ycbcr.sink.stb.eq(self.valid_i), rgb2ycbcr.sink.sop.eq(self.de & ~de_r), rgb2ycbcr.sink.r.eq(self.r), rgb2ycbcr.sink.g.eq(self.g), rgb2ycbcr.sink.b.eq(self.b), Record.connect(rgb2ycbcr.source, chroma_downsampler.sink), chroma_downsampler.source.ack.eq(1), ] # XXX need clean up de = self.de vsync = self.vsync for i in range(rgb2ycbcr.latency + chroma_downsampler.latency): next_de = Signal() next_vsync = Signal() self.sync.pix += [next_de.eq(de), next_vsync.eq(vsync)] de = next_de vsync = next_vsync # start of frame detection vsync_r = Signal() new_frame = Signal() self.comb += new_frame.eq(vsync & ~vsync_r) self.sync.pix += vsync_r.eq(vsync) # pack pixels into words cur_word = Signal(word_width) cur_word_valid = Signal() encoded_pixel = Signal(16) self.comb += (encoded_pixel.eq(Cat(chroma_downsampler.source.y, chroma_downsampler.source.cb_cr)),) pack_factor = word_width // 16 assert pack_factor & (pack_factor - 1) == 0 # only support powers of 2 pack_counter = Signal(max=pack_factor) self.sync.pix += [ cur_word_valid.eq(0), If(new_frame, cur_word_valid.eq(pack_counter == (pack_factor - 1)), pack_counter.eq(0)).Elif( chroma_downsampler.source.stb & de, [ If(pack_counter == (pack_factor - i - 1), cur_word[16 * i : 16 * (i + 1)].eq(encoded_pixel)) for i in range(pack_factor) ], cur_word_valid.eq(pack_counter == (pack_factor - 1)), pack_counter.eq(pack_counter + 1), ), ] # FIFO fifo = RenameClockDomains(AsyncFIFO(word_layout, fifo_depth), {"write": "pix", "read": "sys"}) self.submodules += fifo self.comb += [fifo.din.pixels.eq(cur_word), fifo.we.eq(cur_word_valid)] self.sync.pix += If(new_frame, fifo.din.sof.eq(1)).Elif(cur_word_valid, fifo.din.sof.eq(0)) self.comb += [ self.frame.stb.eq(fifo.readable), self.frame.payload.eq(fifo.dout), fifo.re.eq(self.frame.ack), self.busy.eq(0), ] # overflow detection pix_overflow = Signal() pix_overflow_reset = Signal() self.sync.pix += [If(fifo.we & ~fifo.writable, pix_overflow.eq(1)).Elif(pix_overflow_reset, pix_overflow.eq(0))] sys_overflow = Signal() self.specials += MultiReg(pix_overflow, sys_overflow) self.submodules.overflow_reset = PulseSynchronizer("sys", "pix") self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys") self.comb += [pix_overflow_reset.eq(self.overflow_reset.o), self.overflow_reset_ack.i.eq(pix_overflow_reset)] overflow_mask = Signal() self.comb += [self._overflow.w.eq(sys_overflow & ~overflow_mask), self.overflow_reset.i.eq(self._overflow.re)] self.sync += If(self._overflow.re, overflow_mask.eq(1)).Elif(self.overflow_reset_ack.o, overflow_mask.eq(0))
def __init__(self): self.sink = Sink(line_layout) self.trigger = Signal() self.aux = Signal() self.silence = Signal() self.arm = Signal() self.data = Signal(16) ### line = Record(line_layout) dt_dec = Signal(16) dt_end = Signal(16) dt = Signal(16) adv = Signal() tic = Signal() toc = Signal() stb = Signal() toc0 = Signal() inc = Signal() lp = self.sink.payload self.comb += [ adv.eq(self.arm & self.sink.stb & (self.trigger | ~(line.header.wait | lp.header.trigger))), tic.eq(dt_dec == dt_end), toc.eq(dt == line.dt), stb.eq(tic & toc & adv), self.sink.ack.eq(stb), inc.eq(self.arm & tic & (~toc | (~toc0 & ~adv))), ] subs = [ Volt(lp, stb & (lp.header.typ == 0), inc), Dds(lp, stb & (lp.header.typ == 1), inc), ] for i, sub in enumerate(subs): self.submodules += sub self.sync += [ toc0.eq(toc), self.data.eq(optree("+", [sub.data for sub in subs])), self.aux.eq(line.header.aux), self.silence.eq(line.header.silence), If( ~tic, dt_dec.eq(dt_dec + 1), ).Elif( ~toc, dt_dec.eq(0), dt.eq(dt + 1), ).Elif( stb, line.header.eq(lp.header), line.dt.eq(lp.dt - 1), dt_end.eq((1 << lp.header.shift) - 1), dt_dec.eq(0), dt.eq(0), ) ]
def __init__(self): super(Loopback, self).__init__() self.comb += Record.connect(self.dout, self.din)
def __init__(self, cachesize, lasmim): self.wishbone = wishbone.Interface() ### data_width = flen(self.wishbone.dat_r) if lasmim.dw > data_width and (lasmim.dw % data_width) != 0: raise ValueError("LASMI data width must be a multiple of {dw}".format(dw=data_width)) if lasmim.dw < data_width and (data_width % lasmim.dw) != 0: raise ValueError("WISHBONE data width must be a multiple of {dw}".format(dw=lasmim.dw)) # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(max(lasmim.dw//data_width, 1)) addressbits = lasmim.aw + offsetbits linebits = log2_int(cachesize) - offsetbits tagbits = addressbits - linebits wordbits = data_width//lasmim.dw adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) word = Signal(wordbits) if wordbits else None # Data memory data_mem = Memory(lasmim.dw*2**wordbits, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) self.specials += data_mem, data_port write_from_lasmi = Signal() write_to_lasmi = Signal() if adr_offset is None: adr_offset_r = None else: adr_offset_r = Signal(offsetbits) self.sync += adr_offset_r.eq(adr_offset) self.comb += [ data_port.adr.eq(adr_line), If(write_from_lasmi, displacer(lasmim.dat_r, word, data_port.dat_w), displacer(Replicate(1, lasmim.dw//8), word, data_port.we) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, max(lasmim.dw//data_width, 1))), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_lasmi, chooser(data_port.dat_r, word, lasmim.dat_w), lasmim.dat_we.eq(2**(lasmim.dw//8)-1) ), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) self.specials += tag_mem, tag_port tag_do = Record(tag_layout) tag_di = Record(tag_layout) self.comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] self.comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag) ] if word is not None: self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag)) else: self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag)) # Lasmim word computation, word_clr and word_inc will be simplified # at synthesis when wordbits=0 word_clr = Signal() word_inc = Signal() if word is not None: self.sync += \ If(word_clr, word.eq(0), ).Elif(word_inc, word.eq(word+1) ) def word_is_last(word): if word is not None: return word == 2**wordbits-1 else: return 1 # Control FSM assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1) fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.delayed_enter("EVICT_DATAD", "EVICT_DATA", lasmim.write_latency-1) fsm.delayed_enter("REFILL_DATAD", "REFILL_DATA", lasmim.read_latency-1) fsm.act("IDLE", If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT")) ) fsm.act("TEST_HIT", word_clr.eq(1), If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), NextState("IDLE") ).Else( If(tag_do.dirty, NextState("EVICT_REQUEST") ).Else( NextState("REFILL_WRTAG") ) ) ) fsm.act("EVICT_REQUEST", lasmim.stb.eq(1), lasmim.we.eq(1), If(lasmim.req_ack, NextState("EVICT_WAIT_DATA_ACK")) ) fsm.act("EVICT_WAIT_DATA_ACK", If(lasmim.dat_ack, NextState("EVICT_DATAD")) ) fsm.act("EVICT_DATA", write_to_lasmi.eq(1), word_inc.eq(1), If(word_is_last(word), NextState("REFILL_WRTAG"), ).Else( NextState("EVICT_REQUEST") ) ) fsm.act("REFILL_WRTAG", # Write the tag first to set the LASMI address tag_port.we.eq(1), word_clr.eq(1), NextState("REFILL_REQUEST") ) fsm.act("REFILL_REQUEST", lasmim.stb.eq(1), If(lasmim.req_ack, NextState("REFILL_WAIT_DATA_ACK")) ) fsm.act("REFILL_WAIT_DATA_ACK", If(lasmim.dat_ack, NextState("REFILL_DATAD")) ) fsm.act("REFILL_DATA", write_from_lasmi.eq(1), word_inc.eq(1), If(word_is_last(word), NextState("TEST_HIT"), ).Else( NextState("REFILL_REQUEST") ) )
def get_fragment(self): comb = [] sync = [] aaw = self.asmiport.hub.aw adw = self.asmiport.hub.dw # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(adw//32) addressbits = aaw + offsetbits linebits = log2_int(self.cachesize) - offsetbits tagbits = addressbits - linebits adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) # Data memory data_mem = Memory(adw, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) write_from_asmi = Signal() write_to_asmi = Signal() adr_offset_r = Signal(offsetbits) comb += [ data_port.adr.eq(adr_line), If(write_from_asmi, data_port.dat_w.eq(self.asmiport.dat_r), data_port.we.eq(Replicate(1, adw//8)) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, adw//32)), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_asmi, self.asmiport.dat_w.eq(data_port.dat_r)), self.asmiport.dat_wm.eq(0), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] sync += [ adr_offset_r.eq(adr_offset) ] # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) tag_do = Record(tag_layout) tag_di = Record(tag_layout) comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag), self.asmiport.adr.eq(Cat(adr_line, tag_do.tag)) ] # Control FSM write_to_asmi_pre = Signal() sync.append(write_to_asmi.eq(write_to_asmi_pre)) fsm = FSM("IDLE", "TEST_HIT", "EVICT_ISSUE", "EVICT_WAIT", "REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE") fsm.act(fsm.IDLE, If(self.wishbone.cyc & self.wishbone.stb, fsm.next_state(fsm.TEST_HIT)) ) fsm.act(fsm.TEST_HIT, If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), fsm.next_state(fsm.IDLE) ).Else( If(tag_do.dirty, fsm.next_state(fsm.EVICT_ISSUE) ).Else( fsm.next_state(fsm.REFILL_WRTAG) ) ) ) fsm.act(fsm.EVICT_ISSUE, self.asmiport.stb.eq(1), self.asmiport.we.eq(1), If(self.asmiport.ack, fsm.next_state(fsm.EVICT_WAIT)) ) fsm.act(fsm.EVICT_WAIT, # Data is actually sampled by the memory controller in the next state. # But since the data memory has one cycle latency, it gets the data # at the address given during this cycle. If(self.asmiport.get_call_expression(), write_to_asmi_pre.eq(1), fsm.next_state(fsm.REFILL_WRTAG) ) ) fsm.act(fsm.REFILL_WRTAG, # Write the tag first to set the ASMI address tag_port.we.eq(1), fsm.next_state(fsm.REFILL_ISSUE) ) fsm.act(fsm.REFILL_ISSUE, self.asmiport.stb.eq(1), If(self.asmiport.ack, fsm.next_state(fsm.REFILL_WAIT)) ) fsm.act(fsm.REFILL_WAIT, If(self.asmiport.get_call_expression(), fsm.next_state(fsm.REFILL_COMPLETE)) ) fsm.act(fsm.REFILL_COMPLETE, write_from_asmi.eq(1), fsm.next_state(fsm.TEST_HIT) ) return Fragment(comb, sync, specials={data_mem, tag_mem}) \ + fsm.get_fragment()
self.submodules.tap = wishbone.Tap(self.slave.bus) self.submodules.intercon = wishbone.InterconnectPointToPoint( self.master.bus, self.slave.bus) self.cycle = 0 def gen_reads(self): for a in range(10): t = TRead(a) yield t print("read {} in {} cycles(s)".format(t.data, t.latency)) def do_simulation(self, selfp): if selfp.pads.cs_n: self.cycle = 0 else: self.cycle += 1 if not selfp.slave.dq.oe: selfp.slave.dq.i = self.cycle & 0xf do_simulation.passive = True if __name__ == "__main__": from migen.sim.generic import run_simulation from migen.fhdl import verilog pads = Record([("cs_n", 1), ("clk", 1), ("dq", 4)]) s = SpiFlash(pads) print(verilog.convert(s, ios={pads.clk, pads.cs_n, pads.dq, s.bus.adr, s.bus.dat_r, s.bus.cyc, s.bus.ack, s.bus.stb})) run_simulation(SpiFlashTB(), vcd_name="spiflash.vcd")
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])
def __init__(self, tsc, cri, enable): self.source = stream.Endpoint([("data", message_len)]) self.overflow = CSRStatus() self.overflow_reset = CSR() # # # read_wait_event = cri.i_status[2] read_wait_event_r = Signal() read_done = Signal() read_overflow = Signal() self.sync += read_wait_event_r.eq(read_wait_event) self.comb += \ If(read_wait_event_r & ~read_wait_event, If(~cri.i_status[0], read_done.eq(1)), If(cri.i_status[1], read_overflow.eq(1)) ) input_output_stb = Signal() input_output = Record(input_output_layout) self.comb += [ input_output.channel.eq(cri.chan_sel), input_output.address_padding.eq(cri.o_address), input_output.rtio_counter.eq(tsc.full_ts_cri), If(cri.cmd == cri_commands["write"], input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(cri.o_timestamp), input_output.data.eq(cri.o_data) ).Else( input_output.message_type.eq(MessageType.input.value), input_output.timestamp.eq(cri.i_timestamp), input_output.data.eq(cri.i_data) ), input_output_stb.eq((cri.cmd == cri_commands["write"]) | read_done) ] exception_stb = Signal() exception = Record(exception_layout) self.comb += [ exception.message_type.eq(MessageType.exception.value), exception.channel.eq(cri.chan_sel), exception.rtio_counter.eq(tsc.full_ts_cri), ] just_written = Signal() self.sync += just_written.eq(cri.cmd == cri_commands["write"]) self.comb += [ If(just_written & cri.o_status[1], exception_stb.eq(1), exception.exception_type.eq(ExceptionType.o_underflow.value) ), If(read_overflow, exception_stb.eq(1), exception.exception_type.eq(ExceptionType.i_overflow.value) ) ] stopped = Record(stopped_layout) self.comb += [ stopped.message_type.eq(MessageType.stopped.value), stopped.rtio_counter.eq(tsc.full_ts_cri), ] enable_r = Signal() stopping = Signal() self.sync += [ enable_r.eq(enable), If(~enable & enable_r, stopping.eq(1)), If(~stopping, If(exception_stb, self.source.data.eq(exception.raw_bits()) ).Else( self.source.data.eq(input_output.raw_bits()) ), self.source.eop.eq(0), self.source.stb.eq(enable & (input_output_stb | exception_stb)), If(self.overflow_reset.re, self.overflow.status.eq(0)), If(self.source.stb & ~self.source.ack, self.overflow.status.eq(1) ) ).Else( self.source.data.eq(stopped.raw_bits()), self.source.eop.eq(1), self.source.stb.eq(1), If(self.source.ack, stopping.eq(0)) ) ]
def __init__(self, tsc, cri, enable): self.source = stream.Endpoint([("data", message_len)]) self.overflow = CSRStatus() self.overflow_reset = CSR() # # # read_wait_event = cri.i_status[2] read_wait_event_r = Signal() read_done = Signal() read_overflow = Signal() self.sync += read_wait_event_r.eq(read_wait_event) self.comb += \ If(read_wait_event_r & ~read_wait_event, If(~cri.i_status[0], read_done.eq(1)), If(cri.i_status[1], read_overflow.eq(1)) ) input_output_stb = Signal() input_output = Record(input_output_layout) self.comb += [ input_output.channel.eq(cri.chan_sel), input_output.address_padding.eq(cri.o_address), input_output.rtio_counter.eq(tsc.full_ts_cri), If(cri.cmd == cri_commands["write"], input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(cri.o_timestamp), input_output.data.eq(cri.o_data)).Else( input_output.message_type.eq(MessageType.input.value), input_output.timestamp.eq(cri.i_timestamp), input_output.data.eq(cri.i_data)), input_output_stb.eq((cri.cmd == cri_commands["write"]) | read_done) ] exception_stb = Signal() exception = Record(exception_layout) self.comb += [ exception.message_type.eq(MessageType.exception.value), exception.channel.eq(cri.chan_sel), exception.rtio_counter.eq(tsc.full_ts_cri), ] just_written = Signal() self.sync += just_written.eq(cri.cmd == cri_commands["write"]) self.comb += [ If(just_written & cri.o_status[1], exception_stb.eq(1), exception.exception_type.eq(ExceptionType.o_underflow.value)), If(read_overflow, exception_stb.eq(1), exception.exception_type.eq(ExceptionType.i_overflow.value)) ] stopped = Record(stopped_layout) self.comb += [ stopped.message_type.eq(MessageType.stopped.value), stopped.rtio_counter.eq(tsc.full_ts_cri), ] enable_r = Signal() stopping = Signal() self.sync += [ enable_r.eq(enable), If(~enable & enable_r, stopping.eq(1)), If( ~stopping, If(exception_stb, self.source.data.eq(exception.raw_bits())).Else( self.source.data.eq(input_output.raw_bits())), self.source.eop.eq(0), self.source.stb.eq(enable & (input_output_stb | exception_stb)), If(self.overflow_reset.re, self.overflow.status.eq(0)), If(self.source.stb & ~self.source.ack, self.overflow.status.eq(1))).Else( self.source.data.eq(stopped.raw_bits()), self.source.eop.eq(1), self.source.stb.eq(1), If(self.source.ack, stopping.eq(0))) ]
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, cachesize, lasmim): self.wishbone = wishbone.Interface() ### data_width = flen(self.wishbone.dat_r) if lasmim.dw > data_width and (lasmim.dw % data_width) != 0: raise ValueError( "LASMI data width must be a multiple of {dw}".format( dw=data_width)) if lasmim.dw < data_width and (data_width % lasmim.dw) != 0: raise ValueError( "WISHBONE data width must be a multiple of {dw}".format( dw=lasmim.dw)) # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(max(lasmim.dw // data_width, 1)) addressbits = lasmim.aw + offsetbits linebits = log2_int(cachesize) - offsetbits tagbits = addressbits - linebits wordbits = log2_int(max(data_width // lasmim.dw, 1)) adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) word = Signal(wordbits) if wordbits else None # Data memory data_mem = Memory(lasmim.dw * 2**wordbits, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) self.specials += data_mem, data_port write_from_lasmi = Signal() write_to_lasmi = Signal() if adr_offset is None: adr_offset_r = None else: adr_offset_r = Signal(offsetbits) self.sync += adr_offset_r.eq(adr_offset) self.comb += [ data_port.adr.eq(adr_line), If(write_from_lasmi, displacer(lasmim.dat_r, word, data_port.dat_w), displacer(Replicate(1, lasmim.dw // 8), word, data_port.we)).Else( data_port.dat_w.eq( Replicate(self.wishbone.dat_w, max(lasmim.dw // data_width, 1))), If( self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True))), If(write_to_lasmi, chooser(data_port.dat_r, word, lasmim.dat_w), lasmim.dat_we.eq(2**(lasmim.dw // 8) - 1)), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) self.specials += tag_mem, tag_port tag_do = Record(tag_layout) tag_di = Record(tag_layout) self.comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] self.comb += [tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag)] if word is not None: self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag)) else: self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag)) # Lasmim word computation, word_clr and word_inc will be simplified # at synthesis when wordbits=0 word_clr = Signal() word_inc = Signal() if word is not None: self.sync += \ If(word_clr, word.eq(0), ).Elif(word_inc, word.eq(word+1) ) def word_is_last(word): if word is not None: return word == 2**wordbits - 1 else: return 1 # Control FSM assert (lasmim.write_latency >= 1 and lasmim.read_latency >= 1) fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.delayed_enter("EVICT_DATAD", "EVICT_DATA", lasmim.write_latency - 1) fsm.delayed_enter("REFILL_DATAD", "REFILL_DATA", lasmim.read_latency - 1) fsm.act( "IDLE", If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT"))) fsm.act( "TEST_HIT", word_clr.eq(1), If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1)), NextState("IDLE")).Else( If(tag_do.dirty, NextState("EVICT_REQUEST")).Else( NextState("REFILL_WRTAG")))) fsm.act("EVICT_REQUEST", lasmim.stb.eq(1), lasmim.we.eq(1), If(lasmim.req_ack, NextState("EVICT_WAIT_DATA_ACK"))) fsm.act("EVICT_WAIT_DATA_ACK", If(lasmim.dat_ack, NextState("EVICT_DATAD"))) fsm.act( "EVICT_DATA", write_to_lasmi.eq(1), word_inc.eq(1), If( word_is_last(word), NextState("REFILL_WRTAG"), ).Else(NextState("EVICT_REQUEST"))) fsm.act( "REFILL_WRTAG", # Write the tag first to set the LASMI address tag_port.we.eq(1), word_clr.eq(1), NextState("REFILL_REQUEST")) fsm.act("REFILL_REQUEST", lasmim.stb.eq(1), If(lasmim.req_ack, NextState("REFILL_WAIT_DATA_ACK"))) fsm.act("REFILL_WAIT_DATA_ACK", If(lasmim.dat_ack, NextState("REFILL_DATAD"))) fsm.act( "REFILL_DATA", write_from_lasmi.eq(1), word_inc.eq(1), If( word_is_last(word), NextState("TEST_HIT"), ).Else(NextState("REFILL_REQUEST")))
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, kcsrs, rtio_counter, enable): self.source = stream.Endpoint([("data", message_len)]) self.overflow = CSRStatus() self.overflow_reset = CSR() # # # input_output_stb = Signal() input_output = Record(input_output_layout) o_data = kcsrs.o_data.storage o_address = kcsrs.o_address.storage i_data = kcsrs.i_data.status self.comb += [ input_output.channel.eq(kcsrs.chan_sel.storage), input_output.address_padding.eq(o_address), input_output.rtio_counter.eq(rtio_counter), If(kcsrs.o_we.re, input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(kcsrs.o_timestamp.storage), input_output.data.eq(o_data)).Else( input_output.message_type.eq(MessageType.input.value), input_output.timestamp.eq(kcsrs.i_timestamp.status), input_output.data.eq(i_data)), input_output_stb.eq(kcsrs.o_we.re | kcsrs.i_re.re) ] exception_stb = Signal() exception = Record(exception_layout) self.comb += [ exception.message_type.eq(MessageType.exception.value), exception.channel.eq(kcsrs.chan_sel.storage), exception.rtio_counter.eq(rtio_counter), ] for ename in ("o_underflow_reset", "o_sequence_error_reset", "o_collision_reset", "i_overflow_reset"): self.comb += \ If(getattr(kcsrs, ename).re, exception_stb.eq(1), exception.exception_type.eq( getattr(ExceptionType, ename).value) ) stopped = Record(stopped_layout) self.comb += [ stopped.message_type.eq(MessageType.stopped.value), stopped.rtio_counter.eq(rtio_counter), ] enable_r = Signal() stopping = Signal() self.sync += [ enable_r.eq(enable), If(~enable & enable_r, stopping.eq(1)), If( ~stopping, If(exception_stb, self.source.data.eq(exception.raw_bits())).Else( self.source.data.eq(input_output.raw_bits())), self.source.eop.eq(0), self.source.stb.eq(enable & (input_output_stb | exception_stb)), If(self.overflow_reset.re, self.overflow.status.eq(0)), If(self.source.stb & ~self.source.ack, self.overflow.status.eq(1))).Else( self.source.data.eq(stopped.raw_bits()), self.source.eop.eq(1), self.source.stb.eq(1), If(self.source.ack, stopping.eq(0))) ]
def __init__(self, cachesize, lasmim): self.wishbone = wishbone.Interface() ### if lasmim.dw <= 32: raise ValueError("LASMI data width must be strictly larger than 32") if (lasmim.dw % 32) != 0: raise ValueError("LASMI data width must be a multiple of 32") # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(lasmim.dw//32) addressbits = lasmim.aw + offsetbits linebits = log2_int(cachesize) - offsetbits tagbits = addressbits - linebits adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) # Data memory data_mem = Memory(lasmim.dw, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) self.specials += data_mem, data_port write_from_lasmi = Signal() write_to_lasmi = Signal() adr_offset_r = Signal(offsetbits) self.comb += [ data_port.adr.eq(adr_line), If(write_from_lasmi, data_port.dat_w.eq(lasmim.dat_r), data_port.we.eq(Replicate(1, lasmim.dw//8)) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, lasmim.dw//32)), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_lasmi, lasmim.dat_w.eq(data_port.dat_r), lasmim.dat_we.eq(2**(lasmim.dw//8)-1) ), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] self.sync += adr_offset_r.eq(adr_offset) # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) self.specials += tag_mem, tag_port tag_do = Record(tag_layout) tag_di = Record(tag_layout) self.comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] self.comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag), lasmim.adr.eq(Cat(adr_line, tag_do.tag)) ] # Control FSM assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1) fsm = FSM("IDLE", "TEST_HIT", "EVICT_REQUEST", "EVICT_WAIT_DATA_ACK", "EVICT_DATA", "REFILL_WRTAG", "REFILL_REQUEST", "REFILL_WAIT_DATA_ACK", "REFILL_DATA", delayed_enters=[ ("EVICT_DATAD", "EVICT_DATA", lasmim.write_latency-1), ("REFILL_DATAD", "REFILL_DATA", lasmim.read_latency-1) ]) self.submodules += fsm fsm.act(fsm.IDLE, If(self.wishbone.cyc & self.wishbone.stb, fsm.next_state(fsm.TEST_HIT)) ) fsm.act(fsm.TEST_HIT, If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), fsm.next_state(fsm.IDLE) ).Else( If(tag_do.dirty, fsm.next_state(fsm.EVICT_REQUEST) ).Else( fsm.next_state(fsm.REFILL_WRTAG) ) ) ) fsm.act(fsm.EVICT_REQUEST, lasmim.stb.eq(1), lasmim.we.eq(1), If(lasmim.req_ack, fsm.next_state(fsm.EVICT_WAIT_DATA_ACK)) ) fsm.act(fsm.EVICT_WAIT_DATA_ACK, If(lasmim.dat_ack, fsm.next_state(fsm.EVICT_DATAD)) ) fsm.act(fsm.EVICT_DATA, write_to_lasmi.eq(1), fsm.next_state(fsm.REFILL_WRTAG) ) fsm.act(fsm.REFILL_WRTAG, # Write the tag first to set the LASMI address tag_port.we.eq(1), fsm.next_state(fsm.REFILL_REQUEST) ) fsm.act(fsm.REFILL_REQUEST, lasmim.stb.eq(1), If(lasmim.req_ack, fsm.next_state(fsm.REFILL_WAIT_DATA_ACK)) ) fsm.act(fsm.REFILL_WAIT_DATA_ACK, If(lasmim.dat_ack, fsm.next_state(fsm.REFILL_DATAD)) ) fsm.act(fsm.REFILL_DATA, write_from_lasmi.eq(1), fsm.next_state(fsm.TEST_HIT) )
def __init__(self, sdram, clk_out, clk_sample, databits, rowbits, colbits, bankbits, burst, tRESET, tCL, tRP, tRFC, tRCD, tREFI, tWR): addrbits = rowbits + colbits + bankbits assert sdram.dq.nbits == databits colabits = colbits if colbits <= 10 else colbits + 1 max_col = Replicate(1, colbits) assert sdram.a.nbits >= colabits assert sdram.a.nbits >= rowbits assert sdram.ba.nbits == bankbits dqmbits = max(databits // 8, 1) assert sdram.dqm.nbits == dqmbits assert burst <= 1 << colbits self.hostif = Record(sdramHostIf(databits, addrbits)) # DQ handling, tristate, and sampling dq = TSTriple(databits) self.specials += dq.get_tristate(sdram.dq) dq_r = Signal(databits) self.clock_domains.cd_sample = ClockDomain(reset_less=True) self.comb += self.cd_sample.clk.eq(clk_sample) self.sync.sample += dq_r.eq(dq.i) # Signals used for driving SDRAM control signals # These registered and derived from the current FSM state. # However, the reset state actually determines the default value for # states where they are not explicitly assigned. For example, cmd is # INHIBIT at reset (because the FSM is in RESET state at reset and that # sets cmd to INHIBIT), but it's NOP for every other state where it # isn't assigned. cmd = Signal(4, reset=NOP) dqm = Signal() ba = Signal(bankbits) a = Signal(max(colabits, rowbits)) cke = Signal() sdram.cs_n.reset = 1 self.sync += [ sdram.dqm.eq(Replicate(dqm, dqmbits)), sdram.cs_n.eq(cmd[3]), sdram.ras_n.eq(cmd[2]), sdram.cas_n.eq(cmd[1]), sdram.we_n.eq(cmd[0]), sdram.ba.eq(ba), sdram.a.eq(a), sdram.cke.eq(cke), ] self.comb += [ sdram.clk.eq(clk_out), ] # Counter to time reset cycle of the SDRAM # We enable CKE on the first cycle after system reset, then wait tRESET reset_ctr = Signal(max=tRESET + 1) self.sync += [cke.eq(1), reset_ctr.eq(reset_ctr + 1)] # Counter to time refresh intervals # Note that this can go higher than tREFI, since we might be in the # middle of a burst, but long-term refresh cycles will be issued often # enough to meet refresh timing. refresh_interval = tREFI - 2 # A bit of leeway for safety refresh_ctr = Signal(max=(refresh_interval + 2 * burst + 128)) self.sync += If( cmd == AUTO_REFRESH, If(refresh_ctr > refresh_interval, refresh_ctr.eq(refresh_ctr - refresh_interval)).Else( refresh_ctr.eq(0))).Else(refresh_ctr.eq(refresh_ctr + 1)) tMRD = 3 # JEDEC spec, Micron only needs 2 # Mode: Full page burst mode, burst write mode = 0b0000000111 | (tCL << 4) # last_col indicates that the read/write is about to wrap, and so should end last_col = Signal() i_col_cnt = Signal(colbits) self.comb += last_col.eq(i_col_cnt == max_col) def delay_clocks(v, d): for i in range(d): n = Signal() self.sync += n.eq(v) v = n return v # Read cycle state signals read_cycle = Signal() # Reads come back tCL + 1 clocks later. The extra two cycles # are due to the registration of FIFO outputs and inputs dq_r_sample = Signal(databits) self.sync += dq_r_sample.eq(dq_r) returning_read = delay_clocks(read_cycle, tCL + 2) can_continue_read = Signal() kill_read = Signal() self.comb += [ can_continue_read.eq(~self.hostif.d_term & ~last_col & ~kill_read), self.hostif.d_read.eq(dq_r_sample), ] self.sync += [ # If the output FIFO becomes full, kill the current read If(returning_read & self.hostif.d_term, kill_read.eq(1)).Elif(~returning_read, kill_read.eq(0)), ] # Write state signals write_cycle = Signal() can_continue_write = Signal() self.sync += [ dq.o.eq(self.hostif.d_write), dq.oe.eq(write_cycle), ] self.comb += [ can_continue_write.eq(~self.hostif.d_term & ~last_col), dqm.eq(self.hostif.d_term & write_cycle), ] # Shared signals cmd_needs_reissue = Signal() cmd_reissue = Signal() self.sync += [ If(write_cycle | read_cycle, i_col_cnt.eq(i_col_cnt + 1)), If( ~self.hostif.d_term & last_col & write_cycle | read_cycle & last_col & ~kill_read & ~(returning_read & self.hostif.d_term), cmd_needs_reissue.eq(1)).Elif(cmd_reissue, cmd_needs_reissue.eq(0)) ] # Hostif streaming interface signal generation self.comb += [ self.hostif.d_stb.eq(write_cycle | returning_read & ~kill_read), ] # Address generation def split(addr): col = addr[:colbits] if colbits > 10: col = Cat(col[:10], 0, col[10:]) return col, addr[colbits:colbits + rowbits], addr[colbits + rowbits:] # Issued cmd ptr latch_cmd = Signal() iwr = Signal(1) iptr = Signal(addrbits) i_col, i_row, i_bank = split(iptr) self.sync += If(latch_cmd, iptr.eq(self.hostif.i_addr), iwr.eq(self.hostif.i_wr), i_col_cnt.eq(split(self.hostif.i_addr)[0])).Elif( cmd_reissue, iptr[:colbits].eq(0), iptr[colbits:].eq(iptr[colbits:] + 1), i_col_cnt.eq(0)) # Finite state machine driving the controller fsm = self.submodules.fsm = FSM(reset_state="RESET") # Initialization sequence fsm.act("RESET", cmd.eq(INHIBIT), If(reset_ctr == tRESET, NextState("INIT_IDLE"))) fsm.delayed_enter("INIT_IDLE", "INIT_PRECHARGE", 5) fsm.act("INIT_PRECHARGE", cmd.eq(PRECHARGE), a[10].eq(1)) fsm.delayed_enter("INIT_PRECHARGE", "INIT_REFRESH1", tRP) fsm.act("INIT_REFRESH1", cmd.eq(AUTO_REFRESH)) fsm.delayed_enter("INIT_REFRESH1", "INIT_REFRESH2", tRFC) fsm.act("INIT_REFRESH2", cmd.eq(AUTO_REFRESH)) fsm.delayed_enter("INIT_REFRESH2", "INIT_MODE", tRFC) fsm.act("INIT_MODE", cmd.eq(LOAD_MODE), a.eq(mode)) fsm.delayed_enter("INIT_MODE", "IDLE", tMRD) # Main loop fsm.act( "IDLE", If(refresh_ctr >= refresh_interval, NextState("REFRESH")).Elif( cmd_needs_reissue, cmd_reissue.eq(1), If(iwr, NextState("WRITE_ACTIVE")).Else( NextState("READ_ACTIVE"))).Elif( self.hostif.i_wr & self.hostif.i_stb, self.hostif.i_ack.eq(1), latch_cmd.eq(1), NextState("WRITE_ACTIVE")).Elif( ~self.hostif.i_wr & self.hostif.i_stb, self.hostif.i_ack.eq(1), latch_cmd.eq(1), NextState("READ_ACTIVE"))) # REFRESH fsm.act("REFRESH", cmd.eq(AUTO_REFRESH)) fsm.delayed_enter("REFRESH", "IDLE", tRFC) # WRITE fsm.act("WRITE_ACTIVE", cmd.eq(ACTIVE), ba.eq(i_bank), a.eq(i_row)) fsm.delayed_enter("WRITE_ACTIVE", "WRITE", tRCD) fsm.act( "WRITE", cmd.eq(WRITE), ba.eq(i_bank), a.eq(i_col), write_cycle.eq(1), If(can_continue_write, NextState("WRITING")).Else( If(dqm, NextState("PRECHARGE")).Else(NextState("PRECHARGE_TWR")))) fsm.act( "WRITING", write_cycle.eq(1), If( ~can_continue_write, If(dqm, NextState("PRECHARGE")).Else(NextState("PRECHARGE_TWR")))) # READ fsm.act("READ_ACTIVE", cmd.eq(ACTIVE), ba.eq(i_bank), a.eq(i_row)) fsm.delayed_enter("READ_ACTIVE", "READ", tRCD) fsm.act( "READ", cmd.eq(READ), ba.eq(i_bank), a.eq(i_col), read_cycle.eq(1), If(can_continue_read, NextState("READING")).Else(NextState("PRECHARGE"))) fsm.act("READING", read_cycle.eq(1), If(~can_continue_read, NextState("PRECHARGE"))) if (tWR - 1) > 0: fsm.act("PRECHARGE_TWR", cmd.eq(BURST_TERM)) fsm.delayed_enter("PRECHARGE_TWR", "PRECHARGE", tWR - 1), fsm.act("PRECHARGE", cmd.eq(PRECHARGE), a[10].eq(1)), fsm.delayed_enter("PRECHARGE", "IDLE", tRP)
def __init__(self, rtio_core): self.source = stream.Endpoint([("data", 256)]) self.overflow = CSRStatus() self.overflow_reset = CSR() # # # kcsrs = rtio_core.kcsrs input_output_stb = Signal() input_output = Record(input_output_layout) if hasattr(kcsrs, "o_data"): o_data = kcsrs.o_data.storage else: o_data = 0 if hasattr(kcsrs, "o_address"): o_address = kcsrs.o_address.storage else: o_address = 0 if hasattr(kcsrs, "i_data"): i_data = kcsrs.i_data.status else: i_data = 0 self.comb += [ input_output.channel.eq(kcsrs.chan_sel.storage), input_output.address_padding.eq(o_address), input_output.rtio_counter.eq( rtio_core.counter.value_sys << rtio_core.fine_ts_width), If(kcsrs.o_we.re, input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(kcsrs.o_timestamp.storage), input_output.data.eq(o_data) ).Else( input_output.message_type.eq(MessageType.input.value), input_output.timestamp.eq(kcsrs.i_timestamp.status), input_output.data.eq(i_data) ), input_output_stb.eq(kcsrs.o_we.re | kcsrs.i_re.re) ] exception_stb = Signal() exception = Record(exception_layout) self.comb += [ exception.message_type.eq(MessageType.exception.value), exception.channel.eq(kcsrs.chan_sel.storage), exception.rtio_counter.eq( rtio_core.counter.value_sys << rtio_core.fine_ts_width), ] for ename in ("o_underflow_reset", "o_sequence_error_reset", "o_collision_error_reset", "i_overflow_reset"): self.comb += \ If(getattr(kcsrs, ename).re, exception_stb.eq(1), exception.exception_type.eq( getattr(ExceptionType, ename).value) ) for rname in "reset", "reset_phy": r_d = Signal(reset=1) r = getattr(kcsrs, rname).storage self.sync += r_d.eq(r) self.comb += [ If(r & ~r_d, exception_stb.eq(1), exception.exception_type.eq( getattr(ExceptionType, rname+"_rising").value) ), If(~r & r_d, exception_stb.eq(1), exception.exception_type.eq( getattr(ExceptionType, rname+"_falling").value) ) ] self.sync += [ If(exception_stb, self.source.data.eq(exception.raw_bits()) ).Else( self.source.data.eq(input_output.raw_bits()) ), self.source.stb.eq(input_output_stb | exception_stb) ] self.sync += [ If(self.overflow_reset.re, self.overflow.status.eq(0)), If(self.source.stb & ~self.source.ack, self.overflow.status.eq(1) ) ]
def __init__(self, channels, glbl_fine_ts_width, mode, quash_channels=[], interface=None): if interface is None: interface = cri.Interface() self.cri = interface self.coarse_timestamp = Signal(64 - glbl_fine_ts_width) # # # if mode == "sync": fifo_factory = SyncFIFOBuffered sync_io = self.sync sync_cri = self.sync elif mode == "async": fifo_factory = lambda *args: ClockDomainsRenamer({ "write": "rio", "read": "rsys" })(AsyncFIFO(*args)) sync_io = self.sync.rio sync_cri = self.sync.rsys else: raise ValueError i_statuses, i_datas, i_timestamps = [], [], [] i_ack = Signal() sel = self.cri.chan_sel[:16] for n, channel in enumerate(channels): iif = channel.interface.i if iif is None or n in quash_channels: i_datas.append(0) i_timestamps.append(0) i_statuses.append(0) continue # FIFO layout = get_channel_layout(len(self.coarse_timestamp), iif) fifo = fifo_factory(layout_len(layout), channel.ififo_depth) self.submodules += fifo fifo_in = Record(layout) fifo_out = Record(layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # FIFO write if iif.delay: counter_rtio = Signal.like(self.coarse_timestamp, reset_less=True) sync_io += counter_rtio.eq(self.coarse_timestamp - (iif.delay + 1)) else: counter_rtio = self.coarse_timestamp if hasattr(fifo_in, "data"): self.comb += fifo_in.data.eq(iif.data) if hasattr(fifo_in, "timestamp"): if hasattr(iif, "fine_ts"): full_ts = Cat(iif.fine_ts, counter_rtio) else: full_ts = counter_rtio self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(iif.stb) overflow_io = Signal() self.comb += overflow_io.eq(fifo.we & ~fifo.writable) if mode == "sync": overflow_trigger = overflow_io elif mode == "async": overflow_transfer = BlindTransfer() self.submodules += overflow_transfer self.comb += overflow_transfer.i.eq(overflow_io) overflow_trigger = overflow_transfer.o else: raise ValueError # FIFO read, CRI connection if hasattr(fifo_out, "data"): i_datas.append(fifo_out.data) else: i_datas.append(0) if hasattr(fifo_out, "timestamp"): ts_shift = 64 - len(fifo_out.timestamp) i_timestamps.append(fifo_out.timestamp << ts_shift) else: i_timestamps.append(0) selected = Signal() self.comb += selected.eq(sel == n) overflow = Signal() sync_cri += [ If(selected & i_ack, overflow.eq(0)), If(overflow_trigger, overflow.eq(1)) ] self.comb += fifo.re.eq(selected & i_ack & ~overflow) i_statuses.append(Cat(fifo.readable & ~overflow, overflow)) i_status_raw = Signal(2) self.comb += i_status_raw.eq(Array(i_statuses)[sel]) input_timeout = Signal.like(self.cri.timestamp, reset_less=True) input_pending = Signal() self.cri.i_data.reset_less = True self.cri.i_timestamp.reset_less = True sync_cri += [ i_ack.eq(0), If( i_ack, self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), self.cri.i_data.eq(Array(i_datas)[sel]), self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), ), If((self.cri.counter >= input_timeout) | (i_status_raw != 0), If(input_pending, i_ack.eq(1)), input_pending.eq(0)), If(self.cri.cmd == cri.commands["read"], input_timeout.eq(self.cri.timestamp), input_pending.eq(1), self.cri.i_status.eq(0b100)) ]
def __init__(self, cachesize, lasmim, wbm=None): if wbm is None: wbm = wishbone.Interface() self.wishbone = wbm ### data_width = flen(self.wishbone.dat_r) if lasmim.dw < data_width: raise ValueError("LASMI data width must be >= {dw}".format(dw=data_width)) if (lasmim.dw % data_width) != 0: raise ValueError("LASMI data width must be a multiple of {dw}".format(dw=data_width)) # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(lasmim.dw//data_width) addressbits = lasmim.aw + offsetbits linebits = log2_int(cachesize) - offsetbits tagbits = addressbits - linebits adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits) # Data memory data_mem = Memory(lasmim.dw, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) self.specials += data_mem, data_port write_from_lasmi = Signal() write_to_lasmi = Signal() if adr_offset is None: adr_offset_r = None else: adr_offset_r = Signal(offsetbits) self.sync += adr_offset_r.eq(adr_offset) self.comb += [ data_port.adr.eq(adr_line), If(write_from_lasmi, data_port.dat_w.eq(lasmim.dat_r), data_port.we.eq(Replicate(1, lasmim.dw//8)) ).Else( data_port.dat_w.eq(Replicate(self.wishbone.dat_w, lasmim.dw//data_width)), If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack, displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True) ) ), If(write_to_lasmi, lasmim.dat_w.eq(data_port.dat_r), lasmim.dat_we.eq(2**(lasmim.dw//8)-1) ), chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True) ] # Tag memory tag_layout = [("tag", tagbits), ("dirty", 1)] tag_mem = Memory(layout_len(tag_layout), 2**linebits) tag_port = tag_mem.get_port(write_capable=True) self.specials += tag_mem, tag_port tag_do = Record(tag_layout) tag_di = Record(tag_layout) self.comb += [ tag_do.raw_bits().eq(tag_port.dat_r), tag_port.dat_w.eq(tag_di.raw_bits()) ] self.comb += [ tag_port.adr.eq(adr_line), tag_di.tag.eq(adr_tag), lasmim.adr.eq(Cat(adr_line, tag_do.tag)) ] # Control FSM assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1) fsm = FSM() self.submodules += fsm fsm.delayed_enter("EVICT_DATAD", "EVICT_DATA", lasmim.write_latency-1) fsm.delayed_enter("REFILL_DATAD", "REFILL_DATA", lasmim.read_latency-1) fsm.act("IDLE", If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT")) ) fsm.act("TEST_HIT", If(tag_do.tag == adr_tag, self.wishbone.ack.eq(1), If(self.wishbone.we, tag_di.dirty.eq(1), tag_port.we.eq(1) ), NextState("IDLE") ).Else( If(tag_do.dirty, NextState("EVICT_REQUEST") ).Else( NextState("REFILL_WRTAG") ) ) ) fsm.act("EVICT_REQUEST", lasmim.stb.eq(1), lasmim.we.eq(1), If(lasmim.req_ack, NextState("EVICT_WAIT_DATA_ACK")) ) fsm.act("EVICT_WAIT_DATA_ACK", If(lasmim.dat_ack, NextState("EVICT_DATAD")) ) fsm.act("EVICT_DATA", write_to_lasmi.eq(1), NextState("REFILL_WRTAG") ) fsm.act("REFILL_WRTAG", # Write the tag first to set the LASMI address tag_port.we.eq(1), NextState("REFILL_REQUEST") ) fsm.act("REFILL_REQUEST", lasmim.stb.eq(1), If(lasmim.req_ack, NextState("REFILL_WAIT_DATA_ACK")) ) fsm.act("REFILL_WAIT_DATA_ACK", If(lasmim.dat_ack, NextState("REFILL_DATAD")) ) fsm.act("REFILL_DATA", write_from_lasmi.eq(1), NextState("TEST_HIT") )