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, 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, 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, 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, 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")) )
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, 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, 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, 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, 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, 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 __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, 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, 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, rtio_core, enable): self.source = stream.Endpoint([("data", message_len)]) 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_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)) ] stopped = Record(stopped_layout) self.comb += [ stopped.message_type.eq(MessageType.stopped.value), stopped.rtio_counter.eq( rtio_core.counter.value_sys << rtio_core.fine_ts_width), ] 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() ### 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()
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, 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, 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") )