def __init__(self, interface, counter, fifo_depth): data_width = rtlink.get_data_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) ev_layout = [] if data_width: ev_layout.append(("data", data_width)) if interface.timestamped: ev_layout.append(("timestamp", counter.width + fine_ts_width)) self.ev = Record(ev_layout) self.readable = Signal() self.re = Signal() self.overflow = Signal() # pulsed # # # fifo = ClockDomainsRenamer({ "read": "rsys", "write": "rio" })(AsyncFIFO(layout_len(ev_layout), fifo_depth)) self.submodules += fifo fifo_in = Record(ev_layout) fifo_out = Record(ev_layout) self.comb += [ fifo.din.eq(fifo_in.raw_bits()), fifo_out.raw_bits().eq(fifo.dout) ] # FIFO write if data_width: self.comb += fifo_in.data.eq(interface.data) if interface.timestamped: if fine_ts_width: full_ts = Cat(interface.fine_ts, counter.value_rtio) else: full_ts = counter.value_rtio self.comb += fifo_in.timestamp.eq(full_ts) self.comb += fifo.we.eq(interface.stb) # FIFO read self.comb += [ self.ev.eq(fifo_out), self.readable.eq(fifo.readable), fifo.re.eq(self.re) ] overflow_transfer = _BlindTransfer() self.submodules += overflow_transfer self.comb += [ overflow_transfer.i.eq(fifo.we & ~fifo.writable), self.overflow.eq(overflow_transfer.o), ]
def __init__(self): self.busy = Signal() self.sink = Sink(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, 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 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.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 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 __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 = 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, **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 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): 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 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, 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): 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): 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, 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, 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, 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 UARTPads(): return Record([("tx", 1), ("rx", 1)])
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, 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, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles): self.sel = Signal(max=len(rbus)) # timestamp and value must be valid 1 cycle before we self.timestamp = Signal(counter.width + fine_ts_width) self.value = Signal(2) self.writable = Signal() self.we = Signal() # maximum throughput 1/2 self.underflow = Signal() # valid 2 cycles after we self.underflow_reset = Signal() self.sequence_error = Signal() self.sequence_error_reset = Signal() # # # signal_underflow = Signal() signal_sequence_error = Signal() fifos = [] ev_layout = [("timestamp", counter.width + fine_ts_width), ("value", 2)] for n, chif in enumerate(rbus): # FIFO fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth), { "write": "rsys", "read": "rio" }) self.submodules += fifo fifos.append(fifo) # Buffer buf_pending = Signal() buf = Record(ev_layout) buf_just_written = Signal() # Special cases replace = Signal() sequence_error = Signal() nop = Signal() self.sync.rsys += [ replace.eq(self.timestamp == buf.timestamp[fine_ts_width:]), sequence_error.eq( self.timestamp < buf.timestamp[fine_ts_width:]), nop.eq(self.value == buf.value) ] self.comb += If(self.we & (self.sel == n) & sequence_error, signal_sequence_error.eq(1)) # Buffer read and FIFO write self.comb += fifo.din.eq(buf) in_guard_time = Signal() self.comb += in_guard_time.eq( buf.timestamp[fine_ts_width:] < counter.o_value_sys + guard_io_cycles) self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) self.comb += \ If(buf_pending, If(in_guard_time, If(buf_just_written, signal_underflow.eq(1) ).Else( fifo.we.eq(1) ) ), If((self.we & (self.sel == n) & ~replace & ~nop & ~sequence_error), fifo.we.eq(1) ) ) # Buffer write # Must come after read to handle concurrent read+write properly self.sync.rsys += [ buf_just_written.eq(0), If(self.we & (self.sel == n) & ~nop & ~sequence_error, buf_just_written.eq(1), buf_pending.eq(1), buf.timestamp.eq(self.timestamp), buf.value.eq(self.value)) ] # Buffer output of FIFO to improve timing dout_stb = Signal() dout_ack = Signal() dout = Record(ev_layout) self.sync.rio += \ If(fifo.re, dout_stb.eq(1), dout.eq(fifo.dout) ).Elif(dout_ack, dout_stb.eq(0) ) self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) # FIFO read through buffer self.comb += [ dout_ack.eq( dout.timestamp[fine_ts_width:] == counter.o_value_rio), chif.o_stb.eq(dout_stb & dout_ack), chif.o_value.eq(dout.value) ] if fine_ts_width: self.comb += chif.o_fine_ts.eq(dout.timestamp[:fine_ts_width]) self.comb += \ self.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel]) self.sync.rsys += [ If(self.underflow_reset, self.underflow.eq(0)), If(self.sequence_error_reset, self.sequence_error.eq(0)), If(signal_underflow, self.underflow.eq(1)), If(signal_sequence_error, self.sequence_error.eq(1)) ]
def __init__(self, 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, 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, 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)) ]
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")