def __init__(self, membus): self.enable = CSR() flow_enable = Signal() self.submodules.dma = DMAReader(membus, flow_enable) self.submodules.slicer = RecordSlicer(len(membus.dat_w)) self.submodules.time_offset = TimeOffset() self.submodules.cri_master = CRIMaster() self.cri = self.cri_master.cri self.comb += [ self.dma.source.connect(self.slicer.sink), self.slicer.source.connect(self.time_offset.sink), self.time_offset.source.connect(self.cri_master.sink) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", If(self.enable.re, NextState("FLOWING"))) fsm.act("FLOWING", self.enable.w.eq(1), flow_enable.eq(1), If(self.slicer.end_marker_found, NextState("FLUSH"))) fsm.act("FLUSH", self.enable.w.eq(1), self.slicer.flush.eq(1), NextState("WAIT_EOP")) fsm.act( "WAIT_EOP", self.enable.w.eq(1), If( self.cri_master.sink.stb & self.cri_master.sink.ack & self.cri_master.sink.eop, NextState("WAIT_CRI_MASTER"))) fsm.act("WAIT_CRI_MASTER", self.enable.w.eq(1), If(~self.cri_master.busy, NextState("IDLE")))
def __init__(self, bus_wishbone=None, bus_csr=None): if bus_wishbone is None: bus_wishbone = wishbone.Interface() self.wishbone = bus_wishbone if bus_csr is None: bus_csr = csr_bus.Interface() self.csr = bus_csr self.ack = Signal() self.en = Signal() # # # self.comb += [ self.csr.dat_w.eq(self.wishbone.dat_w), self.wishbone.dat_r.eq(self.csr.dat_r) ] count = Signal(8) fsm = FSM(reset_state="WRITE-READ") self.submodules += fsm fsm.act( "WRITE-READ", If( self.wishbone.cyc & self.wishbone.stb, self.csr.adr.eq(self.wishbone.adr), self.csr.we.eq(self.wishbone.we), self.en.eq(1), NextState("ACK"), )) fsm.act( "ACK", If(self.wishbone.we | self.ack, self.wishbone.ack.eq(1), NextState("WRITE-READ")))
def __init__(self, data_width=44, trigger_id_width=0, length=128): self.data_in = Signal(data_width) self.we = Signal() self.pretrigger = Signal(max=length - 1) self.posttrigger = Signal(max=length - 1) self.trigger = Signal() # trigger_id will be optimized out if not required self.trigger_id = Signal(max(trigger_id_width, 1)) # Trigger ID will be embedded into output data self.data_out = Signal(data_width + trigger_id_width) self.stb_out = Signal() # # # buffer = Memory(data_width + trigger_id_width, length) wr_port = buffer.get_port(write_capable=True) rd_port = buffer.get_port(has_re=True) self.specials += [buffer, wr_port, rd_port] self.wr_ptr = wr_ptr = Signal.like(wr_port.adr) self.rd_ptr = rd_ptr = Signal.like(rd_port.adr) trigger_id_d = Signal.like(self.trigger_id) readout_cnt = Signal(max=length - 1) readout_fsm = FSM("IDLE") self.submodules += readout_fsm readout_fsm.act( "IDLE", If(self.trigger == 1, NextState("READOUT"), NextValue(trigger_id_d, self.trigger_id), NextValue(rd_port.re, 1), NextValue(readout_cnt, self.pretrigger + self.posttrigger + 1)).Else( NextValue(rd_port.re, 0))) readout_fsm.act( "READOUT", If(readout_cnt != 0, NextValue(readout_cnt, readout_cnt - 1), NextValue(rd_port.re, 1), NextValue(self.stb_out, 1)).Else(NextState("IDLE"), NextValue(rd_port.re, 0), NextValue(self.stb_out, 0))) self.comb += [ wr_port.we.eq(self.we), wr_port.adr.eq(wr_ptr), # Will be truncated from left (MSB) wr_port.dat_w.eq(Cat(self.data_in, trigger_id_d)), rd_port.adr.eq(rd_ptr), self.data_out.eq(rd_port.dat_r) ] self.sync += [ If(self.we, rd_ptr.eq(wr_ptr - self.pretrigger), wr_ptr.eq(wr_ptr + 1)) ]
def implement_fsm(states): stnames = ["S" + str(i) for i in range(len(states))] fsm = FSM(*stnames) lans = _LowerAbstractNextState(fsm, states, stnames) for i, state in enumerate(states): actions = lans.visit(state) fsm.act(getattr(fsm, stnames[i]), *actions) return fsm
def __init__(self): self.s = Signal() myfsm = FSM() self.submodules += myfsm myfsm.act("FOO", self.s.eq(1), NextState("BAR")) myfsm.act("BAR", self.s.eq(0), NextState("FOO")) self.be = myfsm.before_entering("FOO") self.ae = myfsm.after_entering("FOO") self.bl = myfsm.before_leaving("FOO") self.al = myfsm.after_leaving("FOO")
def __init__(self, maxlen=65536, data_width=256): self.sink_ctrl = sink_ctrl = stream.Endpoint( self.getControlInterfaceDescriptor(maxlen=maxlen)) self.go = Signal() self.length = Signal(max=maxlen) self.source = source = stream.Endpoint( K2MMPacket.packet_user_description(dw=data_width)) # # # beats = Signal(max=maxlen, reset_less=True) length = Signal.like(sink_ctrl.length) # Status Signal self.busy = busy = Signal() self.sync += busy.eq(sink_ctrl.valid | (sink_ctrl.ready == 0)) # Transition detection _go = Signal.like(self.go) _single_start = Signal() self.sync += _go.eq(self.go) self.comb += _single_start.eq(self.go & ~_go) fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", sink_ctrl.ready.eq(1), If( sink_ctrl.valid | _single_start, NextState("RUN"), NextValue(length, sink_ctrl.length), NextValue(beats, 0), )) _last_sending = Signal() self.comb += _last_sending.eq(beats == length) fsm.act( "RUN", sink_ctrl.ready.eq(0), source.data.eq(Replicate(beats, data_width // len(beats))), source.length.eq((length + 1) * (data_width // 8)), source.pf.eq(1), source.valid.eq(1), source.first.eq(beats == 0), source.last.eq(_last_sending), source.last_be.eq(Replicate(_last_sending, data_width // 8)), If( source.ready == 1, If( _last_sending, NextState("IDLE"), ).Else(NextValue(beats, beats + 1))), ) self.submodules += fsm
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, crc_class, layout): self.sink = sink = Sink(layout) self.source = source = Source(layout) self.busy = Signal() # # # dw = flen(sink.data) crc = crc_class(dw) fsm = FSM(reset_state="IDLE") self.submodules += crc, fsm fsm.act("IDLE", crc.reset.eq(1), sink.ack.eq(1), If(sink.stb & sink.sop, sink.ack.eq(0), NextState("COPY"), ) ) fsm.act("COPY", crc.ce.eq(sink.stb & source.ack), crc.data.eq(sink.data), Record.connect(sink, source), source.eop.eq(0), If(sink.stb & sink.eop & source.ack, NextState("INSERT"), ) ) ratio = crc.width//dw if ratio > 1: cnt = Signal(max=ratio, reset=ratio-1) cnt_done = Signal() fsm.act("INSERT", source.stb.eq(1), chooser(crc.value, cnt, source.data, reverse=True), If(cnt_done, source.eop.eq(1), If(source.ack, NextState("IDLE")) ) ) self.comb += cnt_done.eq(cnt == 0) self.sync += \ If(fsm.ongoing("IDLE"), cnt.eq(cnt.reset) ).Elif(fsm.ongoing("INSERT") & ~cnt_done, cnt.eq(cnt - source.ack) ) else: fsm.act("INSERT", source.stb.eq(1), source.eop.eq(1), source.data.eq(crc.value), If(source.ack, NextState("IDLE")) ) self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
def __init__(self, dw): self.sink = Sink(phy_layout(dw)) self.source = Source(tlp_raw_layout(dw)) ### sink, source = self.sink, self.source sop = Signal() shift = Signal() sink_dat_r = Signal(dw) sink_be_r = Signal(dw // 8) fsm = FSM(reset_state="HEADER1") self.submodules += fsm fsm.act("HEADER1", sink.ack.eq(1), If(sink.stb, shift.eq(1), NextState("HEADER2"))) fsm.act( "HEADER2", sink.ack.eq(1), If( sink.stb, shift.eq(1), If( sink.eop, sink.ack.eq(0), NextState("TERMINATE"), ).Else(NextState("COPY")))) self.sync += [ If(shift, self.source.header.eq(Cat(self.source.header[64:], sink.dat))), If(sink.stb & sink.ack, sink_dat_r.eq(sink.dat), sink_be_r.eq(sink.be)) ] fsm.act( "COPY", sink.ack.eq(source.ack), source.stb.eq(sink.stb), source.sop.eq(sop), source.eop.eq(sink.eop), source.dat.eq( Cat(reverse_bytes(sink_dat_r[32:]), reverse_bytes(sink.dat[:32]))), source.be.eq(Cat(freversed(sink_be_r[4:]), freversed(sink.be[:4]))), If(source.stb & source.ack & source.eop, NextState("HEADER1"))) self.sync += \ If(fsm.before_entering("COPY"), sop.eq(1) ).Elif(source.stb & source.ack, sop.eq(0) ) fsm.act("TERMINATE", sink.ack.eq(source.ack), source.stb.eq(1), source.sop.eq(1), source.eop.eq(1), source.dat.eq(reverse_bytes(sink.dat[32:])), source.be.eq(freversed(sink.be[4:])), If(source.stb & source.ack & source.eop, NextState("HEADER1")))
def __init__(self, membus): self.enable = CSR() flow_enable = Signal() self.submodules.dma = DMAReader(membus, flow_enable) self.submodules.slicer = RecordSlicer(len(membus.dat_w)) self.submodules.time_offset = TimeOffset() self.submodules.cri_master = CRIMaster() self.cri = self.cri_master.cri self.comb += [ self.dma.source.connect(self.slicer.sink), self.slicer.source.connect(self.time_offset.sink), self.time_offset.source.connect(self.cri_master.sink) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", If(self.enable.re, NextState("FLOWING")) ) fsm.act("FLOWING", self.enable.w.eq(1), flow_enable.eq(1), If(self.slicer.end_marker_found, NextState("FLUSH") ) ) fsm.act("FLUSH", self.enable.w.eq(1), self.slicer.flush.eq(1), NextState("WAIT_EOP") ) fsm.act("WAIT_EOP", self.enable.w.eq(1), If(self.cri_master.sink.stb & self.cri_master.sink.ack & self.cri_master.sink.eop, NextState("WAIT_CRI_MASTER") ) ) fsm.act("WAIT_CRI_MASTER", self.enable.w.eq(1), If(~self.cri_master.busy, NextState("IDLE")) )
def __init__(self): self.underflow = CSR() self.error_channel = CSRStatus(24) self.error_timestamp = CSRStatus(64) self.error_address = CSRStatus(16) self.sink = stream.Endpoint(record_layout) self.cri = cri.Interface() self.busy = Signal() # # # underflow_trigger = Signal() self.sync += [ If(underflow_trigger, self.underflow.w.eq(1), self.error_channel.status.eq(self.sink.channel), self.error_timestamp.status.eq(self.sink.timestamp), self.error_address.status.eq(self.sink.address)), If(self.underflow.re, self.underflow.w.eq(0)) ] self.comb += [ self.cri.chan_sel.eq(self.sink.channel), self.cri.timestamp.eq(self.sink.timestamp), self.cri.o_address.eq(self.sink.address), self.cri.o_data.eq(self.sink.data) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act( "IDLE", If( ~self.underflow.w, If( self.sink.stb, If( self.sink.eop, # last packet contains dummy data, discard it self.sink.ack.eq(1)).Else(NextState("WRITE")))).Else( # discard all data until errors are acked self.sink.ack.eq(1))) fsm.act("WRITE", self.busy.eq(1), self.cri.cmd.eq(cri.commands["write"]), NextState("CHECK_STATE")) fsm.act( "CHECK_STATE", self.busy.eq(1), If(self.cri.o_status == 0, self.sink.ack.eq(1), NextState("IDLE")), If(self.cri.o_status[1], NextState("UNDERFLOW"))) fsm.act("UNDERFLOW", self.busy.eq(1), underflow_trigger.eq(1), self.sink.ack.eq(1), NextState("IDLE"))
def __init__(self, sclk, mosi, ncs, value=0x00999a, div=10, por_time=10): fsm = FSM("INIT") self.submodules += [fsm] data = Signal(24) counter = Signal(24, reset=23) por_counter = Signal(max=por_time, reset=por_time) half_bit_counter = Signal(max=div // 2) self.comb += [mosi.eq(data[-1])] fsm.act( "INIT", NextValue(por_counter, por_counter - 1), NextValue(ncs, 1), NextValue(sclk, 0), NextValue(data, value), If(por_counter == 0, NextState("SYNC"), NextValue(half_bit_counter, div // 2), NextValue(ncs, 0))) fsm.act( "SYNC", NextValue(half_bit_counter, half_bit_counter - 1), NextValue(ncs, 0), NextValue(sclk, 0), NextValue(data, value), If(half_bit_counter == 0, NextState("SCLKH"), NextValue(half_bit_counter, div // 2), NextValue(counter, 23))) fsm.act( "SCLKH", NextValue(half_bit_counter, half_bit_counter - 1), NextValue(ncs, 0), NextValue(sclk, 1), If(half_bit_counter == 0, NextState("SCLKL"), NextValue(half_bit_counter, div // 2)), ) fsm.act( "SCLKL", NextValue(half_bit_counter, half_bit_counter - 1), NextValue(ncs, 0), NextValue(sclk, 0), If( half_bit_counter == 0, If(counter == 0, NextState("IDLE")).Else( NextValue(counter, counter - 1), NextState("SCLKH"), NextValue(half_bit_counter, div // 2), NextValue(data, data << 1)))) fsm.act("IDLE", NextValue(ncs, 1), NextValue(sclk, 0))
def __init__(self, sys_clk_freq): self.qpll_reset = Signal() self.qpll_lock = Signal() self.tx_reset = Signal() self.done = Signal() # Handle async signals qpll_reset = Signal() tx_reset = Signal() self.sync += [ self.qpll_reset.eq(qpll_reset), self.tx_reset.eq(tx_reset) ] self.qpll_reset.attr.add("no_retiming") self.tx_reset.attr.add("no_retiming") qpll_lock = Signal() self.specials += MultiReg(self.qpll_lock, qpll_lock) # After configuration, transceiver resets have to stay low for # at least 500ns. # See https://www.xilinx.com/support/answers/43482.html timer_max = ceil(500e-9*sys_clk_freq) timer = Signal(max=timer_max+1) tick = Signal() self.sync += [ tick.eq(0), If(timer == timer_max, tick.eq(1), timer.eq(0) ).Else( timer.eq(timer + 1) ) ] fsm = FSM() self.submodules += fsm fsm.act("WAIT", If(tick, NextState("QPLL_RESET")) ) fsm.act("QPLL_RESET", tx_reset.eq(1), qpll_reset.eq(1), If(tick, NextState("WAIT_QPLL_LOCK")) ) fsm.act("WAIT_QPLL_LOCK", tx_reset.eq(1), If(qpll_lock & tick, NextState("DONE")) ) fsm.act("DONE", self.done.eq(1) )
def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) self.header = Signal(header.length * 8) # # # dw = len(self.sink.data) header_reg = Signal(header.length * 8, reset_less=True) header_words = (header.length * 8) // dw load = Signal() shift = Signal() counter = Signal(max=max(header_words, 2)) counter_reset = Signal() counter_ce = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) self.comb += header.encode(sink, self.header) if header_words == 1: self.sync += [If(load, header_reg.eq(self.header))] else: self.sync += [ If(load, header_reg.eq(self.header)).Elif( shift, header_reg.eq(Cat(header_reg[dw:], Signal(dw)))) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm if header_words == 1: idle_next_state = "COPY" else: idle_next_state = "SEND_HEADER" fsm.act( "IDLE", sink.ready.eq(1), counter_reset.eq(1), If( sink.valid, sink.ready.eq(0), source.valid.eq(1), source.last.eq(0), source.data.eq(self.header[:dw]), If(source.valid & source.ready, load.eq(1), NextState(idle_next_state)))) if header_words != 1: fsm.act( "SEND_HEADER", source.valid.eq(1), source.last.eq(0), source.data.eq(header_reg[dw:2 * dw]), If(source.valid & source.ready, shift.eq(1), counter_ce.eq(1), If(counter == header_words - 2, NextState("COPY")))) if hasattr(sink, "error"): self.comb += source.error.eq(sink.error) fsm.act( "COPY", source.valid.eq(sink.valid), source.last.eq(sink.last), source.data.eq(sink.data), If(source.valid & source.ready, sink.ready.eq(1), If(source.last, NextState("IDLE"))))
def __init__(self, has_completion=True): self.cmd = Endpoint(CMD_REC) self.sink = self.cmd if has_completion: self.completion = Endpoint(CMD_REC) self.source = self.completion self.master = Interface() self.busy = Signal() self.comb += [ self.cmd.ack.eq(0) ] samp_comp = Signal() if has_completion: self.sync += If(self.cmd.ack, self.completion.payload.a.eq(self.cmd.payload.a), self.completion.payload.wr.eq(self.cmd.payload.wr), If(self.cmd.payload.wr, self.completion.payload.d.eq(self.master.dat_w)) ) self.sync += If(samp_comp & ~self.completion.payload.wr, self.completion.payload.d.eq(self.master.dat_r)) fsm = FSM() fsm.act("IDLE", If(self.cmd.stb, self.cmd.ack.eq(1), self.master.we.eq(self.cmd.payload.wr), self.master.adr.eq(self.cmd.payload.a), self.master.dat_w.eq(self.cmd.payload.d), NextState("READ"))) fsm.act("READ", samp_comp.eq(1), NextState("WAIT")) if has_completion: fsm.act("WAIT", self.completion.stb.eq(1), If(self.completion.ack, NextState("IDLE"))) else: fsm.act("WAIT", NextState("IDLE")) self.submodules += fsm
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, crc_class, layout): self.sink = sink = Sink(layout) self.source = source = Source(layout) self.busy = Signal() # # # dw = flen(sink.data) crc = crc_class(dw) fsm = FSM(reset_state="IDLE") self.submodules += crc, fsm fsm.act("IDLE", crc.reset.eq(1), sink.ack.eq(1), If( sink.stb & sink.sop, sink.ack.eq(0), NextState("COPY"), )) fsm.act("COPY", crc.ce.eq(sink.stb & source.ack), crc.data.eq(sink.data), Record.connect(sink, source), source.eop.eq(0), If( sink.stb & sink.eop & source.ack, NextState("INSERT"), )) ratio = crc.width // dw if ratio > 1: cnt = Signal(max=ratio, reset=ratio - 1) cnt_done = Signal() fsm.act( "INSERT", source.stb.eq(1), chooser(crc.value, cnt, source.data, reverse=True), If(cnt_done, source.eop.eq(1), If(source.ack, NextState("IDLE")))) self.comb += cnt_done.eq(cnt == 0) self.sync += \ If(fsm.ongoing("IDLE"), cnt.eq(cnt.reset) ).Elif(fsm.ongoing("INSERT") & ~cnt_done, cnt.eq(cnt - source.ack) ) else: fsm.act("INSERT", source.stb.eq(1), source.eop.eq(1), source.data.eq(crc.value), If(source.ack, NextState("IDLE"))) self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
def __init__(self, in_size, out_size, granularity): g = granularity self.sink = stream.Endpoint([("data", in_size * g)]) self.source = Signal(out_size * g) self.source_stb = Signal() self.source_consume = Signal(max=out_size + 1) self.flush = Signal() self.flush_done = Signal() # # # # worst-case buffer space required (when loading): # <data being shifted out> <new incoming word> buf_size = out_size - 1 + in_size buf = Signal(buf_size * g) self.comb += self.source.eq(buf[:out_size * g]) level = Signal(max=buf_size + 1) next_level = Signal(max=buf_size + 1) self.sync += level.eq(next_level) self.comb += next_level.eq(level) load_buf = Signal() shift_buf = Signal() self.sync += [ If( load_buf, Case( level, { i: buf[i * g:(i + in_size) * g].eq( _reverse_bytes(self.sink.data, g)) for i in range(out_size) })), If( shift_buf, Case(self.source_consume, {i: buf.eq(buf[i * g:]) for i in range(out_size)})), ] fsm = FSM(reset_state="FETCH") self.submodules += fsm fsm.act("FETCH", self.sink.ack.eq(1), load_buf.eq(1), If(self.sink.stb, next_level.eq(level + in_size)), If(next_level >= out_size, NextState("OUTPUT"))) fsm.act("OUTPUT", self.source_stb.eq(1), shift_buf.eq(1), next_level.eq(level - self.source_consume), If(next_level < out_size, NextState("FETCH")), If(self.flush, NextState("FLUSH"))) fsm.act( "FLUSH", next_level.eq(0), self.sink.ack.eq(1), If(self.sink.stb & self.sink.eop, self.flush_done.eq(1), NextState("FETCH")))
def __init__(self, ulpi_reg): ReadAddress = Signal(6) write_fsm = FSM() self.submodules += write_fsm def delay_clocks(v, d): for i in range(d): n = Signal() self.sync += n.eq(v) v = n return v ulpi_reg_wack = delay_clocks(ulpi_reg.wack, 2) ulpi_reg_rack = delay_clocks(ulpi_reg.rack, 2) write_fsm.delayed_enter("RESET", "WRITE_HS_SNOOP", 16) write_fsm.act("WRITE_HS_SNOOP", ulpi_reg.waddr.eq(0x4), ulpi_reg.wdata.eq(0x48), ulpi_reg.wreq.eq(1), If(ulpi_reg_wack, NextState("WRITE_IDLE"))) write_fsm.act("WRITE_IDLE", ulpi_reg.wreq.eq(0)) read_fsm = FSM() self.submodules += read_fsm read_fsm.delayed_enter("RESET", "READ_REG", 16) read_fsm.act("READ_REG", ulpi_reg.raddr.eq(ReadAddress), ulpi_reg.rreq.eq(1), If(ulpi_reg_rack, NextState("READ_ACK"))) self.sync += If(ulpi_reg_rack & ulpi_reg.rreq, ReadAddress.eq(ReadAddress + 1)) read_fsm.act("READ_ACK", ulpi_reg.rreq.eq(0), If(~ulpi_reg_rack, NextState("READ_WAIT"))) read_fsm.delayed_enter("READ_WAIT", "READ_REG", 16)
def __init__(self, crc_class, layout): self.sink = sink = Sink(layout) self.source = source = Source(layout) self.busy = Signal() # # # dw = flen(sink.data) crc = crc_class(dw) self.submodules += crc ratio = crc.width // dw error = Signal() fifo = InsertReset(SyncFIFO(layout, ratio + 1)) self.submodules += fifo fsm = FSM(reset_state="RESET") self.submodules += fsm fifo_in = Signal() fifo_out = Signal() fifo_full = Signal() self.comb += [ fifo_full.eq(fifo.fifo.level == ratio), fifo_in.eq(sink.stb & (~fifo_full | fifo_out)), fifo_out.eq(source.stb & source.ack), Record.connect(sink, fifo.sink), fifo.sink.stb.eq(fifo_in), self.sink.ack.eq(fifo_in), source.stb.eq(sink.stb & fifo_full), source.sop.eq(fifo.source.sop), source.eop.eq(sink.eop), fifo.source.ack.eq(fifo_out), source.payload.eq(fifo.source.payload), source.error.eq(sink.error | crc.error), ] fsm.act( "RESET", crc.reset.eq(1), fifo.reset.eq(1), NextState("IDLE"), ) fsm.act( "IDLE", crc.data.eq(sink.data), If(sink.stb & sink.sop & sink.ack, crc.ce.eq(1), NextState("COPY"))) fsm.act( "COPY", crc.data.eq(sink.data), If(sink.stb & sink.ack, crc.ce.eq(1), If(sink.eop, NextState("RESET")))) self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
def __init__(self, clock_pads, pads): self._reset = CSRStorage() # # # self.clock_domains.cd_eth_rx = ClockDomain() self.clock_domains.cd_eth_tx = ClockDomain() # RX dcm_reset = Signal() dcm_locked = Signal() timer = WaitTimer(1024) fsm = FSM(reset_state="DCM_RESET") self.submodules += timer, fsm fsm.act("DCM_RESET", dcm_reset.eq(1), timer.wait.eq(1), If(timer.done, timer.wait.eq(0), NextState("DCM_WAIT"))) fsm.act("DCM_WAIT", timer.wait.eq(1), If(timer.done, NextState("DCM_CHECK_LOCK"))) fsm.act("DCM_CHECK_LOCK", If(~dcm_locked, NextState("DCM_RESET"))) clk90_rx = Signal() clk0_rx = Signal() clk0_rx_bufg = Signal() self.specials += Instance("DCM", i_CLKIN=clock_pads.rx, i_CLKFB=clk0_rx_bufg, o_CLK0=clk0_rx, o_CLK90=clk90_rx, o_LOCKED=dcm_locked, i_PSEN=0, i_PSCLK=0, i_PSINCDEC=0, i_RST=dcm_reset) self.specials += Instance("BUFG", i_I=clk0_rx, o_O=clk0_rx_bufg) self.specials += Instance("BUFG", i_I=clk90_rx, o_O=self.cd_eth_rx.clk) # TX self.specials += DDROutput(1, 0, clock_pads.tx, ClockSignal("eth_tx")) self.specials += Instance("BUFG", i_I=self.cd_eth_rx.clk, o_O=self.cd_eth_tx.clk) # Reset reset = self._reset.storage self.comb += pads.rst_n.eq(~reset) self.specials += [ AsyncResetSynchronizer(self.cd_eth_tx, reset), AsyncResetSynchronizer(self.cd_eth_rx, reset), ]
def __init__(self, pads): self.source = source = Source(eth_description(8)) ### sop = source.sop set_sop = Signal() clr_sop = Signal() self.sync += \ If(clr_sop, sop.eq(0) ).Elif(set_sop, sop.eq(1) ) lo = Signal(4) hi = Signal(4) load_nibble = Signal(2) self.sync += \ If(load_nibble[0], lo.eq(pads.rx_data) ).Elif(load_nibble[1], hi.eq(pads.rx_data) ) self.comb += [ source.d.eq(Cat(lo, hi)) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", set_sop.eq(1), If(pads.dv, load_nibble.eq(0b01), NextState("LOAD_HI") ) ) fsm.act("LOAD_LO", source.stb.eq(1), If(pads.dv, clr_sop.eq(1), load_nibble.eq(0b01), NextState("LOAD_HI") ).Else( source.eop.eq(1), NextState("IDLE") ) ) fsm.act("LOAD_HI", load_nibble.eq(0b10), NextState("LOAD_LO") )
def __init__(self): self.busy=Signal() self.sink = Sink([('d',8)]) self.source = Source(CMD_REC) sm = FSM(reset_state="IDLE") self.submodules += sm # Basic checksum token = self.source.payload token_next = Record(CMD_REC) self.sync += token.eq(token_next) self.comb += token_next.eq(token) sm.act("IDLE", self.sink.ack.eq(1), If(self.sink.stb, If(self.sink.payload.d == 0x55, NextState("ADRH") ))) def parse_state(st, to, *update): sm.act(st, self.sink.ack.eq(1), If(self.sink.stb, NextState(to), *update )) parse_state('ADRH', 'ADRL', token_next.wr.eq(self.sink.payload.d[7]), token_next.a[8:14].eq(self.sink.payload.d[:6])) parse_state('ADRL', 'DATA', token_next.a[0:8].eq(self.sink.payload.d)), parse_state('DATA', 'CKSUM', token_next.d.eq(self.sink.payload.d)), sm.act("CKSUM", self.sink.ack.eq(1), If(self.sink.stb, NextState('ISSUE') ) ) sm.act("ISSUE", self.source.stb.eq(1), If(self.source.ack, NextState('IDLE')))
def __init__(self, sys_clk_freq): self.qpll_reset = Signal() self.qpll_lock = Signal() self.tx_reset = Signal() self.done = Signal() # Handle async signals qpll_reset = Signal() tx_reset = Signal() self.sync += [ self.qpll_reset.eq(qpll_reset), self.tx_reset.eq(tx_reset) ] self.qpll_reset.attr.add("no_retiming") self.tx_reset.attr.add("no_retiming") qpll_lock = Signal() self.specials += MultiReg(self.qpll_lock, qpll_lock) # After configuration, transceiver resets have to stay low for # at least 500ns. # See https://www.xilinx.com/support/answers/43482.html timer_max = ceil(500e-9 * sys_clk_freq) timer = Signal(max=timer_max + 1) tick = Signal() self.sync += [ tick.eq(0), If(timer == timer_max, tick.eq(1), timer.eq(0)).Else(timer.eq(timer + 1)) ] fsm = FSM() self.submodules += fsm fsm.act("WAIT", If(tick, NextState("QPLL_RESET"))) fsm.act("QPLL_RESET", tx_reset.eq(1), qpll_reset.eq(1), If(tick, NextState("WAIT_QPLL_LOCK"))) fsm.act("WAIT_QPLL_LOCK", tx_reset.eq(1), If(qpll_lock & tick, NextState("DONE"))) fsm.act("DONE", self.done.eq(1))
def __init__(self): self.counter = Signal(8) myfsm = FSM() self.submodules += myfsm self.sync += self.counter.eq(self.counter + 1) self.sync += If(self.counter > 235, myfsm.act("COAST", If(self.counter == 240, NextState("IDLE")) )) myfsm.act("IDLE", If(self.counter == 10, NextState("START")) ) myfsm.act("START", If(self.counter == 100, NextState("RUNNING")) ) myfsm.act("RUNNING", If(self.counter == 200, NextState("COAST")) )
def __init__(self, d_w): self.sink = Sink(eth_description(d_w)) self.source = Source(eth_description(d_w)) ### preamble = Signal(64, reset=eth_preamble) cnt_max = (64//d_w)-1 cnt = Signal(max=cnt_max+1) clr_cnt = Signal() inc_cnt = Signal() self.sync += \ If(clr_cnt, cnt.eq(0) ).Elif(inc_cnt, cnt.eq(cnt+1) ) fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", self.sink.ack.eq(1), clr_cnt.eq(1), If(self.sink.stb & self.sink.sop, self.sink.ack.eq(0), NextState("INSERT"), ) ) fsm.act("INSERT", self.source.stb.eq(1), self.source.sop.eq(cnt==0), chooser(preamble, cnt, self.source.d), If(cnt == cnt_max, If(self.source.ack, NextState("COPY")) ).Else( inc_cnt.eq(self.source.ack) ) ) fsm.act("COPY", Record.connect(self.sink, self.source), self.source.sop.eq(0), If(self.sink.stb & self.sink.eop & self.source.ack, NextState("IDLE"), ) )
def __init__(self, max_size, buffered=True): self.sink = sink = Sink(descriptor_layout()) if buffered: self.submodules.buffer = Buffer(descriptor_layout(True)) source = self.buffer.d self.source = self.buffer.q else: self.source = source = Source(descriptor_layout(True)) # # # offset = Signal(32) clr_offset = Signal() inc_offset = Signal() self.sync += \ If(clr_offset, offset.eq(0) ).Elif(inc_offset, offset.eq(offset + max_size) ) user_id = Signal(8) self.sync += \ If(sink.stb & sink.ack, user_id.eq(user_id+1) ) fsm = FSM(reset_state="IDLE") self.submodules += fsm length = Signal(16) update_length = Signal() self.sync += If(update_length, length.eq(sink.length)) fsm.act( "IDLE", sink.ack.eq(1), clr_offset.eq(1), If(sink.stb, update_length.eq(1), sink.ack.eq(0), NextState("RUN"))) fsm.act( "RUN", source.stb.eq(1), source.address.eq(sink.address + offset), source.user_id.eq(user_id), If((length - offset) > max_size, source.length.eq(max_size), inc_offset.eq(source.ack)).Else( source.length.eq(length - offset), If(source.ack, NextState("ACK")))) fsm.act("ACK", sink.ack.eq(1), NextState("IDLE"))
def __init__(self, dw): self.sink = sink = Sink(tlp_raw_layout(dw)) self.source = source = Source(phy_layout(dw)) ### fsm = FSM(reset_state="HEADER1") self.submodules += fsm sink_dat_r = Signal(dw) sink_eop_r = Signal() self.sync += \ If(sink.stb & sink.ack, sink_dat_r.eq(sink.dat), sink_eop_r.eq(sink.eop) ) fsm.act( "HEADER1", sink.ack.eq(1), If(sink.stb & sink.sop, sink.ack.eq(0), source.stb.eq(1), source.sop.eq(1), source.eop.eq(0), source.dat.eq(sink.header[:64]), source.be.eq(0xff), If( source.stb & source.ack, NextState("HEADER2"), ))) fsm.act( "HEADER2", source.stb.eq(1), source.sop.eq(0), source.eop.eq(sink.eop), source.dat.eq(Cat(sink.header[64:96], reverse_bytes(sink.dat[:32]))), source.be.eq(Cat(Signal(4, reset=0xf), freversed(sink.be[:4]))), If(source.stb & source.ack, sink.ack.eq(1), If(source.eop, NextState("HEADER1")).Else(NextState("COPY")))) fsm.act( "COPY", source.stb.eq(sink.stb | sink_eop_r), source.sop.eq(0), source.eop.eq(sink_eop_r), source.dat.eq( Cat(reverse_bytes(sink_dat_r[32:64]), reverse_bytes(sink.dat[:32]))), If(sink_eop_r, source.be.eq(0x0f)).Else(source.be.eq(0xff)), If(source.stb & source.ack, sink.ack.eq(~sink_eop_r), If(source.eop, NextState("HEADER1"))))
def __init__(self, a, ba, tRP, tREFI, tRFC): self.req = Signal() self.ack = Signal() # 1st command 1 cycle after assertion of ack self.cmd = CommandRequest(a, ba) ### # Refresh sequence generator: # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done seq_start = Signal() seq_done = Signal() self.sync += [ self.cmd.a.eq(2**10), self.cmd.ba.eq(0), self.cmd.cas_n.eq(1), self.cmd.ras_n.eq(1), self.cmd.we_n.eq(1), seq_done.eq(0) ] self.sync += timeline( seq_start, [(1, [self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0)]), (1 + tRP, [self.cmd.cas_n.eq(0), self.cmd.ras_n.eq(0)]), (1 + tRP + tRFC, [seq_done.eq(1)])]) # Periodic refresh counter counter = Signal(max=tREFI) start = Signal() self.sync += [ start.eq(0), If(counter == 0, start.eq(1), counter.eq(tREFI - 1)).Else(counter.eq(counter - 1)) ] # Control FSM fsm = FSM() self.submodules += fsm fsm.act("IDLE", If(start, NextState("WAIT_GRANT"))) fsm.act("WAIT_GRANT", self.req.eq(1), If(self.ack, seq_start.eq(1), NextState("WAIT_SEQ"))) fsm.act("WAIT_SEQ", self.req.eq(1), If(seq_done, NextState("IDLE")))
def __init__(self, pads): self.sink = sink = Sink(eth_description(8)) ### tx_en_r = Signal() tx_data_r = Signal(4) self.sync += [ pads.tx_er.eq(0), pads.tx_en.eq(tx_en_r), pads.tx_data.eq(tx_data_r), ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", sink.ack.eq(1), If(sink.stb & sink.sop, sink.ack.eq(0), NextState("SEND_LO") ) ) fsm.act("SEND_LO", tx_data_r.eq(sink.d[0:4]), tx_en_r.eq(1), NextState("SEND_HI") ) fsm.act("SEND_HI", tx_data_r.eq(sink.d[4:8]), tx_en_r.eq(1), sink.ack.eq(1), If(sink.stb & sink.eop, NextState("IDLE") ).Else( NextState("SEND_LO") ) )
def __init__(self, crc_class, layout): self.sink = sink = Sink(layout, True) self.source = source = Source(layout, True) self.busy = Signal() ### dw = flen(sink.d) self.submodules.crc = crc_class(dw) fsm = FSM(reset_state="RESET_CRC") self.submodules += fsm fsm.act("RESET_CRC", sink.ack.eq(0), self.crc.reset.eq(1), NextState("IDLE") ) fsm.act("IDLE", sink.ack.eq(sink.stb), If(sink.stb & sink.sop, Record.connect(sink, source), self.crc.ce.eq(sink.ack), self.crc.d.eq(sink.d), NextState("COPY") ) ) fsm.act("COPY", Record.connect(sink, source), self.crc.ce.eq(sink.stb & sink.ack), self.crc.d.eq(sink.d), source.error.eq(sink.eop & self.crc.error), If(sink.stb & sink.ack & sink.eop, NextState("RESET_CRC") ) ) self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
def __init__(self, ulpi_bus, ulpi_reg): ulpi_data_out = Signal(8) ulpi_data_tristate = Signal() ulpi_data_next = Signal(8) ulpi_data_tristate_next = Signal() ulpi_stp_next = Signal() ulpi_state_rx = Signal() ulpi_state_rrd = Signal() self.data_out_source = Endpoint(ULPI_DATA_D) RegWriteReqR = Signal() RegReadReqR = Signal() RegWriteReq = Signal() RegReadReq = Signal() RegReadAckSet = Signal() RegWriteAckSet = Signal() # register the reg read/write requests self.sync += RegReadReqR.eq(ulpi_reg.rreq) self.sync += RegWriteReqR.eq(ulpi_reg.wreq) # signal when read/write is requested but not done self.comb += RegReadReq.eq(RegReadReqR & ~ulpi_reg.rack) v = (RegReadReqR & ~ulpi_reg.rack) self.comb += RegWriteReq.eq(RegWriteReqR & ~ulpi_reg.wack) # ack logic: set ack=0 when req=0, set ack=1 when access done self.sync += If(~RegReadReqR, ulpi_reg.rack.eq(0) ).Elif(RegReadAckSet, ulpi_reg.rack.eq(1)) self.sync += If(~RegWriteReqR, ulpi_reg.wack.eq(0) ).Elif(RegWriteAckSet, ulpi_reg.wack.eq(1)) exp = If(~RegWriteReqR, ulpi_reg.wack.eq(0)).Elif(RegWriteAckSet, ulpi_reg.wack.eq(1)) # output data if required by state self.comb += ulpi_bus.stp.eq(ulpi_stp_next) self.comb += ulpi_data_out.eq(ulpi_data_next) self.comb += ulpi_data_tristate.eq(ulpi_data_tristate_next) self.comb += ulpi_bus.do.eq(ulpi_data_out) self.comb += ulpi_bus.doe.eq(~ulpi_data_tristate) # capture RX data at the end of RX, but only if no turnaround was requested # We also support "stuffing" data, to indicate conditions such as: # - Simultaneous DIR + NXT assertion # (the spec doesn't require an RXCMD - DIR+NXT asserting may be the' # only SOP signal) # - End-of-packet # (Packets may end without an RXCMD, unless an error occurs) ulpi_rx_stuff = Signal() ulpi_rx_stuff_d = Signal(8) self.sync += self.data_out_source.stb.eq(1) self.sync += If(ulpi_rx_stuff, self.data_out_source.payload.d.eq(ulpi_rx_stuff_d), self.data_out_source.payload.rxcmd.eq(1) ).Elif(ulpi_state_rx & ulpi_bus.dir, If(~ulpi_bus.nxt, self.data_out_source.payload.d.eq(ulpi_bus.di & RXCMD_MASK), self.data_out_source.payload.rxcmd.eq(1) ).Else( self.data_out_source.payload.d.eq(ulpi_bus.di), self.data_out_source.payload.rxcmd.eq(0) ) ).Else( self.data_out_source.payload.d.eq(RXCMD_MAGIC_NOP), self.data_out_source.payload.rxcmd.eq(1) ) # capture register reads at the end of RRD self.sync += If(ulpi_state_rrd,ulpi_reg.rdata.eq(ulpi_bus.di)) fsm = FSM() self.submodules += fsm fsm.act("IDLE", ulpi_data_next.eq(0x00), # NOOP ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0), If(~ulpi_bus.dir & ~ulpi_bus.nxt & ~(RegWriteReq | RegReadReq), NextState("IDLE") ).Elif(ulpi_bus.dir, # TA, and then either RXCMD or Data NextState("RX"), ulpi_data_tristate_next.eq(1), # If dir & nxt, we're starting a packet, so stuff a custom SOP If(ulpi_bus.nxt, ulpi_rx_stuff.eq(1), ulpi_rx_stuff_d.eq(RXCMD_MAGIC_SOP) ) ).Elif(RegWriteReq, NextState("RW0"), ulpi_data_next.eq(0x80 | ulpi_reg.waddr), # REGW ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0) ).Elif(RegReadReq, NextState("RR0"), ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0) ).Else( NextState("ERROR") )) fsm.act("RX", If(ulpi_bus.dir, # stay in RX NextState("RX"), ulpi_state_rx.eq(1), ulpi_data_tristate_next.eq(1) ).Else( # TA back to idle # Stuff an EOP on return to idle ulpi_rx_stuff.eq(1), ulpi_rx_stuff_d.eq(RXCMD_MAGIC_EOP), ulpi_data_tristate_next.eq(0), NextState("IDLE") )) fsm.act("RW0", If(ulpi_bus.dir, NextState("RX"), ulpi_data_tristate_next.eq(1), ).Elif(~ulpi_bus.dir, ulpi_data_next.eq(0x80 | ulpi_reg.waddr), # REGW ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0), If(ulpi_bus.nxt, NextState("RWD")).Else(NextState("RW0")), ).Else( NextState("ERROR") )) fsm.act("RWD", If(ulpi_bus.dir, NextState("RX"), ulpi_data_tristate_next.eq(1) ).Elif(~ulpi_bus.dir & ulpi_bus.nxt, NextState("RWS"), ulpi_data_next.eq(ulpi_reg.wdata), ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0) ).Else( NextState("ERROR") ), ) fsm.act("RWS", If(~ulpi_bus.dir, NextState("IDLE"), ulpi_data_next.eq(0x00), # NOOP ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(1), RegWriteAckSet.eq(1) ).Elif(ulpi_bus.dir, NextState("RX"), ulpi_data_tristate_next.eq(1), ), ) fsm.act("RR0", If(~ulpi_bus.dir, ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR NextState("RR1") ).Elif(ulpi_bus.dir, NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") )) fsm.act("RR1", If(~ulpi_bus.dir & ulpi_bus.nxt, # PHY accepts REGR ulpi_data_tristate_next.eq(1), # TA NextState("RR2") ).Elif(~ulpi_bus.dir & ~ulpi_bus.nxt, # PHY delays REGR ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR NextState("RR1") ).Elif(ulpi_bus.dir, NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") )) fsm.act("RR2", ulpi_data_tristate_next.eq(1), If(~ulpi_bus.nxt, # REGR continue NextState("RRD") ).Elif(ulpi_bus.dir, # PHY indicates RX NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") )) fsm.act("RRD", If(ulpi_bus.dir & ~ulpi_bus.nxt, NextState("IDLE"), RegReadAckSet.eq(1), ulpi_state_rrd.eq(1), ).Elif(ulpi_bus.dir & ulpi_bus.nxt, NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") ), ulpi_data_tristate_next.eq(1), ) fsm.act("ERROR", NextState("IDLE"))
def __init__(self, ulpi_bus): self.ulpi_bus = ulpi_bus fsm = FSM() self.submodules += fsm self.WantRx = Signal() self.RxByte = Signal(8) self.RxCmd = Signal() self.NextCycleRx = Signal() self.RegWriteValid = Signal() self.RegAddrW = Signal(6) self.RegDataW = Signal(8) self.RegRead = Signal() self.RegAddrR = Signal(6) self.RegDataR = Signal(8) self.StateTX = Signal() SetRegAddrR = Signal() SetRegAddrW = Signal() SetRegDataW = Signal() fsm.act("TXCMD", If(self.WantRx, NextState("TA1") ).Elif(ulpi_bus.do[6:8] == 0b10, NextState("RW0") # REGW ).Elif(ulpi_bus.do[6:8] == 0b11, NextState("RR0") # REGR ).Else(NextState("TXCMD"), ulpi_bus.dir.eq(0), self.StateTX.eq(1) )) fsm.act("TA1", NextState("RX"), ulpi_bus.dir.eq(1), self.NextCycleRx.eq(1) ) fsm.act("RX", If(self.WantRx, NextState("RX"), ulpi_bus.dir.eq(1), ulpi_bus.di.eq(self.RxByte), ulpi_bus.nxt.eq(self.RxCmd), self.NextCycleRx.eq(1) ).Else(NextState("TA2") )) fsm.act("TA2", NextState("TXCMD"), ulpi_bus.dir.eq(0) ) fsm.act("RW0", If(self.WantRx, NextState("TA1") ).Else( NextState("RW1"), ulpi_bus.dir.eq(0), ulpi_bus.nxt.eq(1), SetRegAddrW.eq(1) )) fsm.act("RW1", NextState("RW2"), ulpi_bus.dir.eq(0), ulpi_bus.nxt.eq(1), SetRegDataW.eq(1) ) fsm.act("RW2", NextState("TXCMD"), self.RegWriteValid.eq(ulpi_bus.stp)) fsm.act("RR0", If(self.WantRx, NextState("TA1") ).Else( NextState("RR1"), SetRegAddrR.eq(1), ulpi_bus.nxt.eq(1), )) fsm.act("RR1", ulpi_bus.dir.eq(1), If(self.WantRx, NextState("RX"), ulpi_bus.nxt.eq(1), # indicating abort ).Else( NextState("RRD") )) fsm.act("RRD", ulpi_bus.dir.eq(1), ulpi_bus.di.eq(self.RegDataR), NextState("TA2" )) self.sync += If(SetRegAddrR, self.RegAddrR.eq(ulpi_bus.do[0:6])) self.sync += self.RegRead.eq(SetRegAddrR) self.sync += If(SetRegAddrW, self.RegAddrW.eq(ulpi_bus.do[0:6])) self.sync += If(SetRegDataW, self.RegDataW.eq(ulpi_bus.do))
def __init__(self, sink_description, source_description, header): self.sink = sink = Sink(sink_description) self.source = source = Source(source_description) self.header = Signal(header.length*8) # # # dw = flen(sink.data) header_words = (header.length*8)//dw shift = Signal() counter = Counter(max=max(header_words, 2)) self.submodules += counter if header_words == 1: self.sync += \ If(shift, self.header.eq(sink.data) ) else: self.sync += \ If(shift, self.header.eq(Cat(self.header[dw:], sink.data)) ) fsm = FSM(reset_state="IDLE") self.submodules += fsm if header_words == 1: idle_next_state = "COPY" else: idle_next_state = "RECEIVE_HEADER" fsm.act("IDLE", sink.ack.eq(1), counter.reset.eq(1), If(sink.stb, shift.eq(1), NextState(idle_next_state) ) ) if header_words != 1: fsm.act("RECEIVE_HEADER", sink.ack.eq(1), If(sink.stb, counter.ce.eq(1), shift.eq(1), If(counter.value == header_words-2, NextState("COPY") ) ) ) no_payload = Signal() self.sync += \ If(fsm.before_entering("COPY"), source.sop.eq(1), no_payload.eq(sink.eop) ).Elif(source.stb & source.ack, source.sop.eq(0) ) self.comb += [ source.eop.eq(sink.eop | no_payload), source.data.eq(sink.data), source.error.eq(sink.error), header.decode(self.header, source) ] fsm.act("COPY", sink.ack.eq(source.ack), source.stb.eq(sink.stb | no_payload), If(source.stb & source.ack & source.eop, NextState("IDLE") ) )
def __init__(self, geom_settings, timing_settings, address_align, bankn, req): self.refresh_req = Signal() self.refresh_gnt = Signal() self.cmd = CommandRequestRW(geom_settings.mux_a, geom_settings.bank_a) ### # Request FIFO self.submodules.req_fifo = SyncFIFO([("we", 1), ("adr", flen(req.adr))], timing_settings.req_queue_size) self.comb += [ self.req_fifo.din.we.eq(req.we), self.req_fifo.din.adr.eq(req.adr), self.req_fifo.we.eq(req.stb), req.req_ack.eq(self.req_fifo.writable), self.req_fifo.re.eq(req.dat_ack), req.lock.eq(self.req_fifo.readable), ] reqf = self.req_fifo.dout slicer = _AddressSlicer(geom_settings.col_a, address_align) # Row tracking has_openrow = Signal() openrow = Signal(geom_settings.row_a) hit = Signal() self.comb += hit.eq(openrow == slicer.row(reqf.adr)) track_open = Signal() track_close = Signal() self.sync += [ If(track_open, has_openrow.eq(1), openrow.eq(slicer.row(reqf.adr))), If(track_close, has_openrow.eq(0)), ] # Address generation s_row_adr = Signal() self.comb += [ self.cmd.ba.eq(bankn), If(s_row_adr, self.cmd.a.eq(slicer.row(reqf.adr))).Else(self.cmd.a.eq(slicer.col(reqf.adr))), ] # Respect write-to-precharge specification precharge_ok = Signal() t_unsafe_precharge = 2 + timing_settings.tWR - 1 unsafe_precharge_count = Signal(max=t_unsafe_precharge + 1) self.comb += precharge_ok.eq(unsafe_precharge_count == 0) self.sync += [ If(self.cmd.stb & self.cmd.ack & self.cmd.is_write, unsafe_precharge_count.eq(t_unsafe_precharge)).Elif( ~precharge_ok, unsafe_precharge_count.eq(unsafe_precharge_count - 1) ) ] # Control and command generation FSM fsm = FSM() self.submodules += fsm fsm.act( "REGULAR", If(self.refresh_req, NextState("REFRESH")).Elif( self.req_fifo.readable, If( has_openrow, If( hit, # NB: write-to-read specification is enforced by multiplexer self.cmd.stb.eq(1), req.dat_ack.eq(self.cmd.ack), self.cmd.is_read.eq(~reqf.we), self.cmd.is_write.eq(reqf.we), self.cmd.cas_n.eq(0), self.cmd.we_n.eq(~reqf.we), ).Else(NextState("PRECHARGE")), ).Else(NextState("ACTIVATE")), ), ) fsm.act( "PRECHARGE", # Notes: # 1. we are presenting the column address, A10 is always low # 2. since we always go to the ACTIVATE state, we do not need # to assert track_close. If( precharge_ok, self.cmd.stb.eq(1), If(self.cmd.ack, NextState("TRP")), self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0), self.cmd.is_cmd.eq(1), ), ) fsm.act( "ACTIVATE", s_row_adr.eq(1), track_open.eq(1), self.cmd.stb.eq(1), self.cmd.is_cmd.eq(1), If(self.cmd.ack, NextState("TRCD")), self.cmd.ras_n.eq(0), ) fsm.act( "REFRESH", self.refresh_gnt.eq(precharge_ok), track_close.eq(1), self.cmd.is_cmd.eq(1), If(~self.refresh_req, NextState("REGULAR")), ) fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP - 1) fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD - 1)
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 __init__(self, sys_clk_freq): self.rx_reset = Signal() self.rx_pma_reset_done = Signal() # DRPCLK must be driven by the system clock self.drpaddr = Signal(9) self.drpen = Signal() self.drpdi = Signal(16) self.drprdy = Signal() self.drpdo = Signal(16) self.drpwe = Signal() self.enable = Signal() self.restart = Signal() self.done = Signal() # Handle async signals rx_reset = Signal() self.sync += self.rx_reset.eq(rx_reset) self.rx_reset.attr.add("no_retiming") rx_pma_reset_done = Signal() self.specials += MultiReg(self.rx_pma_reset_done, rx_pma_reset_done) drpvalue = Signal(16) drpmask = Signal() self.comb += [ self.drpaddr.eq(0x011), If(drpmask, self.drpdi.eq(drpvalue & 0xf7ff)).Else(self.drpdi.eq(drpvalue)) ] rx_pma_reset_done_r = Signal() self.sync += rx_pma_reset_done_r.eq(rx_pma_reset_done) fsm = FSM() self.submodules += fsm fsm.act("WAIT_ENABLE", If(self.enable, NextState("GTRXRESET"))) fsm.act("GTRXRESET", rx_reset.eq(1), NextState("DRP_READ_ISSUE")) fsm.act("DRP_READ_ISSUE", rx_reset.eq(1), self.drpen.eq(1), NextState("DRP_READ_WAIT")) fsm.act( "DRP_READ_WAIT", rx_reset.eq(1), If(self.drprdy, NextValue(drpvalue, self.drpdo), NextState("DRP_MOD_ISSUE"))) fsm.act("DRP_MOD_ISSUE", rx_reset.eq(1), drpmask.eq(1), self.drpen.eq(1), self.drpwe.eq(1), NextState("DRP_MOD_WAIT")) fsm.act("DRP_MOD_WAIT", rx_reset.eq(1), If(self.drprdy, NextState("WAIT_PMARST_FALL"))) fsm.act( "WAIT_PMARST_FALL", If(rx_pma_reset_done_r & ~rx_pma_reset_done, NextState("DRP_RESTORE_ISSUE"))) fsm.act("DRP_RESTORE_ISSUE", self.drpen.eq(1), self.drpwe.eq(1), NextState("DRP_RESTORE_WAIT")) fsm.act("DRP_RESTORE_WAIT", If(self.drprdy, NextState("DONE"))) fsm.act("DONE", self.done.eq(1), If(self.restart, NextState("WAIT_ENABLE")))
def __init__(self, pads): self.background = ModuleDoc( """MemLCD: Driver for the SHARP Memory LCD model LS032B7DD02 The LS032B7DD02 is a 336x536 pixel black and white memory LCD, with a 200ppi dot pitch. Memory LCDs can be thought of as 'fast E-ink displays that consume a tiny bit of standby power', as seen by these properties: * Extremely low standby power (30uW typ hold mode) * No special bias circuitry required to maintain image in hold mode * 120 degree viewing angle, 1:35 contrast ratio * All control logic fabricated on-glass using TFT devices that are auditable with a common 40x power desktop microscope and a bright backlight source This last property in particular makes the memory LCD extremely well suited for situations where absolute visibility into the construction of a secure enclave is desired. The memory organization of the LS032B7DD02 is simple: 536 lines of pixel data 336 wide. Each pixel is 1 bit (the display is black and white), and is fed into the module from left to right as pixels 1 through 336, inclusive. Lines are enumerated from top to bottom, from 1 to 536, inclusive. The LCD can only receive serial data. The protocol is a synchronous serial interface with an active high chip select. All data words are transmitted LSB first. A line transfer is initiated by sending a 6-bit mode selection, a 10-bit row address, and the subsequent 336 pixels, followed by 16 dummy bits which transfer the data from the LCD holding register to the display itself. .. wavedrom:: :caption: Single line data transfer to memory LCD { "signal": [ { "name": "SCLK", "wave": "0.P.......|......|...|..l." }, { "name": "SCS", "wave": "01........|......|...|.0.." }, { "name": "SI", "wave": "0===x..===|======|==x|....", "data": ["M0", "M1", "M2", "R0", "R1", " ", "R8", "R9", "D0", "D1", "D2", " ", "D334", "D335"] }, { "node": ".....................a.b..."}, ], "edge": ['a<->b 16 cycles'] } Alternatively, one can send successive lines without dropping SCS by substituting the 16 dummy bits at the end with a 6-bit don't care preamble (where the mode bits would have been), 10 bits of row address, and then the pixel data. .. wavedrom:: :caption: Multiple line data transfer to memory LCD { "signal": [ { "name": "SCLK", "wave": "0.P.......|......|...|....|....." }, { "name": "SCS", "wave": "01........|......|...|....|....." }, { "name": "SI", "wave": "0===x..===|======|==x|.===|=====", "data": ["M0", "M1", "M2", "R0", "R1", " ", "R8", "R9", "D0", "D1", "D2", " ", "D334", "D335", "R0", "R1", " ", "R8", "R9", "D0", "D1"] }, { "node": ".....................a.b..."}, ], "edge": ['a<->b 6 cycles'] } The very last line in the multiple line data transfer must terminate with 16 dummy cycles. Mode bits M0-M2 have the following meaning: M0: Set to 1 when transferring data lines. Set to 0 for hold mode, see below. M1: VCOM inversion flag. Ignore when hardware strap pin EXTMODE is high. Betrusted sets EXTMODE high, so the VCOM inversion is handled by low-power aux hardware. When EXTMODE is low, software must explicitly manage the VCOM inversion flag such the flag polarity changes once every second "as much as possible". M2: Normally set to 0. Set to 1 for all clear (see below) Data bit polarity: 1 = White 0 = Black For 'Hold mode' and 'All clear', a total of 16 cycles are sent, the first three being the mode bit and the last 13 being dummy cycles. .. wavedrom:: :caption: Hold and all clear timings { "signal": [ { "name": "SCLK", "wave": "0.P...|.l" }, { "name": "SCS", "wave": "01....|0." }, { "name": "SI", "wave": "0===x...", "data": ["M0", "M1", "M2", "R0", "R1", " ", "R8", "R9", "D0", "D1", "D2", " ", "D334", "D335", "R0", "R1", " ", "R8", "R9", "D0", "D1"] }, { "node": ".....a.b..."}, ], "edge": ['a<->b 13 cycles'] } All signals are 3.0V compatible, 5V tolerant (VIH is 2.7V-VDD). The display itself requires a single 5V power supply (4.8-5.5V typ 5.8V abs max). In hold mode, typical power is 30uW, max 330uW; with data updating at 1Hz, power is 250uW, max 750uW (SCLK=1MHz, EXTCOMMIN=1Hz). * The maximum clock frequency for SCLK is 2MHz (typ 1MHz). * EXTCOMMIN frequency is 1-10Hz, 1Hz typ * EXTCOMMIN minimum high duration is 1us * All rise/fall times must be less than 50ns * SCS setup time is 3us, hold time is 1us. Minimum low duration is 1us, minimum high is 188us for a data update, 12 us for a hold mode operation. * SI setup time is 120ns, 190ns hold time. * Operating temperature is -20 to 70C, storage temperature -30 to 80C. """) self.interface = ModuleDoc("""Wishbone interface for MemLCD MemLCD maintains a local framebuffer for the LCD. The CPU can read and write to the frame buffer to update pixel data, and then request a screen update to commit the frame buffer to the LCD. Only full lines can be updated on a memory LCD; partial updates are not possible. In order to optimize the update process, MemLCD maintains a "dirty bit" associated with each line. Only lines with modified pixels are written to the screen after an update request. A line is 336 bits wide. When padded to 32-bit words, this yields a line width of 44 bytes (0x2C, or 352 bits). In order to simplify math, the frame buffer rounds the line width up to the nearest power of two, or 64 bytes. The unused bits can be used as a "hint" to the MemLCD block as to which lines require updating. If the unused bits have any value other than 0, the MemLCD block will update those lines when an "UpdateDirty" command is triggered. It is up to the CPU to set and clear the dirty bits, they are not automatically cleared by the block upon update. Typically the clearing of the bits would be handled during the update-finished interrupt handling routine. If the dirty bits are not used, an "UpdateAll" command can be invoked, which will update every line of the LCD regardless of the contents of the dirty bits. The total depth of the memory is thus 44 bytes * 536 lines = 23,584 bytes or 5,896 words. Pixels are stored with the left-most pixel in the MSB of each 32-bit word, with the left-most pixels occupying the lowest address in the line. Lines are stored with the bottom line of the screen at the lowest address. These parameters are chosen so that a 1-bit BMP file can be copied into the frame buffer and it will render directly to the screen with no further transformations required. The CPU is responsible for not writing data to the LCD while it is updating. Concurrent writes to the LCD during updates can lead to unpredictable behavior. """) data_width = 32 width = 336 height = 536 bytes_per_line = 44 self.fb_depth = fb_depth = height * bytes_per_line // (data_width // 8) pixdata = Signal(32) pixadr_rd = Signal(max=fb_depth) # 1 is white, which is the "off" state fb_init = [0xffffffff] * int(fb_depth) for i in range(fb_depth // 11): fb_init[i * 11 + 10] = 0xffff mem = Memory( 32, fb_depth, init=fb_init ) # may need to round up to 8192 if a power of 2 is required by migen # read port for pixel data out self.specials.rdport = mem.get_port( write_capable=False, mode=READ_FIRST) # READ_FIRST allows BRAM to be used self.comb += self.rdport.adr.eq(pixadr_rd) self.comb += pixdata.eq(self.rdport.dat_r) # implementation note: vivado will complain about being unable to merge an output register, leading to # non-optimal timing, but a check of the timing path shows that at 100MHz there is about 4-5ns of setup margin, # so the merge is unnecessary in this case. Ergo, prefer comb over sync to reduce latency. # memory-mapped write port to wishbone bus self.bus = wishbone.Interface() self.submodules.wb_sram_if = wishbone.SRAM(mem, read_only=False) decoder_offset = log2_int(fb_depth, need_pow2=False) def slave_filter(a): return a[decoder_offset:32 - decoder_offset] == 0 # no aliasing in the block self.submodules.wb_con = wishbone.Decoder( self.bus, [(slave_filter, self.wb_sram_if.bus)], register=True) self.command = CSRStorage( 2, fields=[ CSRField( "UpdateDirty", description="Write a ``1`` to flush dirty lines to the LCD", pulse=True), CSRField( "UpdateAll", description="Update full screen regardless of tag state", pulse=True), ]) self.busy = CSRStatus( 1, name="Busy", description= """A ``1`` indicates that the block is currently updating the LCD""" ) self.prescaler = CSRStorage(8, reset=99, name="prescaler", description=""" Prescaler value. LCD clock is module (clock / (prescaler+1)). Reset value: 99, so for a default sysclk of 100MHz this yields an LCD SCLK of 1MHz""") self.submodules.ev = EventManager() self.ev.done = EventSourceProcess() self.ev.finalize() self.comb += self.ev.done.trigger.eq( self.busy.status) # Fire an interupt when busy drops self.sclk = sclk = getattr(pads, "sclk") self.scs = scs = getattr(pads, "scs") self.si = si = getattr(pads, "si") self.sendline = sendline = Signal() self.linedone = linedone = Signal() updateall = Signal() fetch_dirty = Signal() update_line = Signal( max=height ) # Keep track of both line and address to avoid instantiating a multiplier update_addr = Signal(max=height * bytes_per_line) fsm_up = FSM(reset_state="IDLE") self.submodules += fsm_up fsm_up.act( "IDLE", If( self.command.fields.UpdateDirty | self.command.fields.UpdateAll, NextValue(self.busy.status, 1), NextValue(fetch_dirty, 1), If(self.command.fields.UpdateAll, NextValue(updateall, 1)).Else(NextValue(updateall, 0)), NextState("START")).Else(NextValue(self.busy.status, 0))) fsm_up.act( "START", NextValue(update_line, height), NextValue( update_addr, (height - 1) * bytes_per_line ), # Represents the byte address of the beginning of the last line NextState("FETCHDIRTY")) fsm_up.act( "FETCHDIRTY", # Wait one cycle delay for the pixel data to be retrieved before evaluating it NextState("CHECKDIRTY")) fsm_up.act( "CHECKDIRTY", If(update_line == 0, NextState("IDLE")).Else( If( (pixdata[16:] != 0) | updateall, NextState("DIRTYLINE"), ).Else(NextValue(update_line, update_line - 1), NextValue(update_addr, update_addr - bytes_per_line), NextState("FETCHDIRTY")))) fsm_up.act("DIRTYLINE", NextValue(fetch_dirty, 0), sendline.eq(1), NextState("WAITDONE")) fsm_up.act( "WAITDONE", If(linedone, NextValue(fetch_dirty, 1), NextValue(update_line, update_line - 1), NextValue(update_addr, update_addr - bytes_per_line), NextState("FETCHDIRTY"))) modeshift = Signal(16) mode = Signal(6) pixshift = Signal(32) pixcount = Signal(max=width) bitreq = Signal() bitack = Signal() self.comb += mode.eq( 1 ) # Always in line write mode, not clearing, no vcom management necessary fsm_phy = FSM(reset_state="IDLE") self.submodules += fsm_phy # Update_addr units is in bytes. [2:] turns bytes to words # pixcount units are in pixels. [3:] turns pixels to bytes self.comb += [ If(fetch_dirty, pixadr_rd.eq( (update_addr + bytes_per_line - 4)[2:])).Else( pixadr_rd.eq((update_addr + pixcount[3:])[2:])) ] scs_cnt = Signal(max=200) fsm_phy.act( "IDLE", NextValue(si, 0), NextValue(linedone, 0), If( sendline, NextValue(scs, 1), NextValue(scs_cnt, 200), # 2 us setup NextValue(pixcount, 16), NextValue(modeshift, Cat(mode, update_line)), NextState("SCS_SETUP")).Else(NextValue(scs, 0))) fsm_phy.act( "SCS_SETUP", If(scs_cnt > 0, NextValue(scs_cnt, scs_cnt - 1)).Else(NextState("MODELINE"))) fsm_phy.act( "MODELINE", If(pixcount > 0, NextValue(modeshift, modeshift[1:]), NextValue(si, modeshift[0]), NextValue(pixcount, pixcount - 1), bitreq.eq(1), NextState("MODELINEWAIT")).Else(NextValue(pixcount, 1), NextValue(pixshift, pixdata), NextState("DATA"))) fsm_phy.act("MODELINEWAIT", If(bitack, NextState("MODELINE"))) fsm_phy.act( "DATA", If( pixcount < width + 17, If( pixcount[0:5] == 0, NextValue(pixshift, pixdata), ).Else(NextValue(pixshift, pixshift[1:]), ), NextValue(scs, 1), NextValue(si, pixshift[0]), NextValue(pixcount, pixcount + 1), bitreq.eq(1), NextState("DATAWAIT")).Else( NextValue(si, 0), NextValue(scs_cnt, 100), # 1 us hold NextState("SCS_HOLD"))) fsm_phy.act( "SCS_HOLD", If(scs_cnt > 0, NextValue(scs_cnt, scs_cnt - 1)).Else( NextValue(scs, 0), NextValue(scs_cnt, 100), # 1us minimum low time NextState("SCS_LOW"))) fsm_phy.act( "SCS_LOW", If(scs_cnt > 0, NextValue(scs_cnt, scs_cnt - 1)).Else(NextValue(linedone, 1), NextState("IDLE"))) fsm_phy.act("DATAWAIT", If(bitack, NextState("DATA"))) # This handles clock division fsm_bit = FSM(reset_state="IDLE") self.submodules += fsm_bit clkcnt = Signal(8) fsm_bit.act("IDLE", NextValue(sclk, 0), NextValue(clkcnt, self.prescaler.storage), If(bitreq, NextState("SCLK_LO"))) fsm_bit.act( "SCLK_LO", NextValue(clkcnt, clkcnt - 1), If(clkcnt < self.prescaler.storage[1:], NextValue(sclk, 1), NextState("SCLK_HI"))) fsm_bit.act( "SCLK_HI", NextValue(clkcnt, clkcnt - 1), If(clkcnt == 0, NextValue(sclk, 0), NextState("IDLE"), bitack.eq(1)))
def __init__(self, rx0, tx0, rx1, tx1, rd_port, wr_port, c_pci_data_width=32, wordsize=32, ptrsize=64, npagesincache=4, pagesize=4096): self.cmd_rx = rx0 self.cmd_tx = tx0 self.data_rx = rx1 self.data_tx = tx1 self.rd_port = rd_port self.wr_port = wr_port self.virt_addr = Signal(ptrsize) self.page_addr = Signal(log2_int(npagesincache)) self.send_req = Signal() self.fetch_req = Signal() self.req_complete = Signal() ## # fix start signals cmd_rx_start_prev = Signal() data_rx_start_prev = Signal() self.sync += cmd_rx_start_prev.eq(self.cmd_rx.start), data_rx_start_prev.eq(self.data_rx.start) cmd_rx_transaction_requested = Signal() data_rx_transaction_requested = Signal() cmd_rx_transaction_ack = Signal() data_rx_transaction_ack = Signal() self.sync += If(cmd_rx_transaction_ack, cmd_rx_transaction_requested.eq(0)).Elif(~cmd_rx_transaction_requested & (self.cmd_rx.start == 1) & (cmd_rx_start_prev == 0), cmd_rx_transaction_requested.eq(1)) self.sync += If(data_rx_transaction_ack, data_rx_transaction_requested.eq(0)).Elif(~data_rx_transaction_requested & (self.data_rx.start == 1) & (data_rx_start_prev == 0), data_rx_transaction_requested.eq(1)) # constant definitions memorywidth = max(c_pci_data_width, wordsize) memorysize = npagesincache*pagesize*8//memorywidth pcie_word_adr_nbits = log2_int(memorywidth//32) num_tx_off = log2_int(c_pci_data_width//32) num_tx_per_word = max(1, wordsize//c_pci_data_width) words_per_line = c_pci_data_width//wordsize if c_pci_data_width > wordsize else wordsize//c_pci_data_width page_adr_nbits = log2_int(npagesincache) line_adr_nbits = log2_int(pagesize*8//memorywidth) word_adr_nbits = log2_int(words_per_line) byte_adr_nbits = log2_int(wordsize//8) word_adr_off = byte_adr_nbits line_adr_off = log2_int(memorywidth//8) page_tag_off = line_adr_nbits + line_adr_off page_tag_nbits = ptrsize - page_tag_off # variables virt_addr_internal = Signal(ptrsize) page_addr_internal = Signal(ptrsize) rxcount = Signal(32) txcount = Signal(32) wordcount = Signal(32) rlen = Signal(32) # state machine that controls page cache fsm = FSM() self.submodules += fsm fsm.act("IDLE", #0 #reset internal registers NextValue(rxcount, 0), NextValue(txcount, 0), NextValue(wordcount, 0), NextValue(rlen, 0), self.req_complete.eq(1), If(self.send_req, NextValue(virt_addr_internal, self.virt_addr), NextValue(page_addr_internal, self.page_addr), NextState("TX_DIRTY_PAGE_INIT") ).Elif(self.fetch_req, NextValue(virt_addr_internal, self.virt_addr), NextValue(page_addr_internal, self.page_addr), NextState("TX_PAGE_FETCH_CMD") ) ) fsm.act("REQ_COMPLETE", self.req_complete.eq(1), NextState("IDLE") ) # page send fsm.act("TX_DIRTY_PAGE_INIT", #4 self.data_tx.start.eq(1), self.data_tx.len.eq(pagesize//4), self.data_tx.last.eq(1), NextValue(txcount, c_pci_data_width//32), NextValue(wordcount, 0), If(self.data_tx.ack, rd_port.adr.eq(0), rd_port.adr[-page_adr_nbits:].eq(page_addr_internal), rd_port.re.eq(1), NextState("TX_DIRTY_PAGE") ) ) fsm.act("TX_DIRTY_PAGE", #5 self.data_tx.start.eq(1), self.data_tx.len.eq(pagesize//4), self.data_tx.last.eq(1), self.data_tx.data_valid.eq(1), self.data_tx.data.eq(rd_port.dat_r) if c_pci_data_width >= wordsize else [If(i == wordcount[:word_adr_nbits], self.data_tx.data.eq(rd_port.dat_r[i*c_pci_data_width:(i+1)*c_pci_data_width])) for i in range(num_tx_per_word)], If(self.data_tx.data_ren, NextValue(txcount, txcount + c_pci_data_width//32), NextValue(wordcount, wordcount + 1), If(txcount < (pagesize//4), rd_port.adr[0: line_adr_nbits].eq(txcount[pcie_word_adr_nbits:pcie_word_adr_nbits + line_adr_nbits]), rd_port.adr[-page_adr_nbits:].eq(page_addr_internal), rd_port.re.eq(1) ).Else( NextState("TX_WRITEBACK_CMD") ) ) ) page_writeback_cmd = Signal(128) self.comb += page_writeback_cmd[64:128].eq(0x61B061B061B061B0), page_writeback_cmd[page_tag_off:64].eq(virt_addr_internal[page_tag_off:64]) fsm.act("TX_WRITEBACK_CMD", #2 self.cmd_tx.start.eq(1), self.cmd_tx.len.eq(4), self.cmd_tx.last.eq(1), If(self.cmd_tx.ack, NextState("TX_WRITEBACK_CMD0") ) ) for i in range(128//c_pci_data_width): fsm.act("TX_WRITEBACK_CMD" + str(i), #3 self.cmd_tx.start.eq(1), self.cmd_tx.len.eq(4), self.cmd_tx.last.eq(1), self.cmd_tx.data.eq(page_writeback_cmd[i*c_pci_data_width:(i+1)*c_pci_data_width]), self.cmd_tx.data_valid.eq(1), If(self.cmd_tx.data_ren, NextState("TX_WRITEBACK_CMD" + str(i+1)) if i+1 < 128//c_pci_data_width else NextState("REQ_COMPLETE") ) ) # page fetch page_fetch_cmd = Signal(128) self.comb += page_fetch_cmd[64: 128].eq(0x6E706E706E706E70), page_fetch_cmd[page_tag_off: 64].eq(virt_addr_internal[page_tag_off:]) fsm.act("TX_PAGE_FETCH_CMD", #6 self.cmd_tx.start.eq(1), self.cmd_tx.len.eq(4), self.cmd_tx.last.eq(1), If(self.cmd_tx.ack, NextState("TX_PAGE_FETCH_CMD0") ) ) for i in range(128//c_pci_data_width): fsm.act("TX_PAGE_FETCH_CMD" + str(i), #7 self.cmd_tx.start.eq(1), self.cmd_tx.len.eq(4), self.cmd_tx.last.eq(1), self.cmd_tx.data.eq(page_fetch_cmd[i*c_pci_data_width:(i+1)*c_pci_data_width]), self.cmd_tx.data_valid.eq(1), If(self.cmd_tx.data_ren, NextState("TX_PAGE_FETCH_CMD" + str(i+1)) if i+1 < 128//c_pci_data_width else NextState("RX_WAIT") ) ) fsm.act("RX_WAIT", #8 NextValue(rxcount, 0), If(data_rx_transaction_requested, NextValue(rlen, self.data_rx.len), NextState("RX_PAGE") ) ) fsm.act("RX_PAGE", #9 self.data_rx.ack.eq(1), data_rx_transaction_ack.eq(1), wr_port.dat_w.eq(Cat([self.data_rx.data for i in range(num_tx_per_word)])), wr_port.adr[0:line_adr_nbits].eq(rxcount[pcie_word_adr_nbits: pcie_word_adr_nbits + line_adr_nbits]), wr_port.adr[-page_adr_nbits:].eq(page_addr_internal), If(self.data_rx.data_valid, self.data_rx.data_ren.eq(1), [wr_port.we[i].eq(1) for i in range(c_pci_data_width//wordsize)] if c_pci_data_width >= wordsize else wr_port.we.eq(1 << rxcount[num_tx_off: num_tx_off + word_adr_nbits]), NextValue(rxcount, rxcount + c_pci_data_width//32), If((rxcount >= (pagesize*8 - c_pci_data_width)//32) | (rxcount >= rlen - c_pci_data_width//32), NextState("REQ_COMPLETE") ) ) )
def __init__(self, lasmim, nslots): bus_aw = lasmim.aw bus_dw = lasmim.dw alignment_bits = bits_for(bus_dw//8) - 1 fifo_word_width = 24*bus_dw//32 self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)]) self._r_frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits) self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits) self.ev = self._slot_array.ev ### # address generator + maximum memory word count to prevent DMA buffer overrun reset_words = Signal() count_word = Signal() last_word = Signal() current_address = Signal(bus_aw) mwords_remaining = Signal(bus_aw) self.comb += [ self._slot_array.address_reached.eq(current_address), last_word.eq(mwords_remaining == 1) ] self.sync += [ If(reset_words, current_address.eq(self._slot_array.address), mwords_remaining.eq(self._r_frame_size.storage) ).Elif(count_word, current_address.eq(current_address + 1), mwords_remaining.eq(mwords_remaining - 1) ) ] # 24bpp -> 32bpp memory_word = Signal(bus_dw) pixbits = [] for i in range(bus_dw//32): for j in range(3): b = (i*3+j)*8 pixbits.append(self.frame.payload.pixels[b+6:b+8]) pixbits.append(self.frame.payload.pixels[b:b+8]) pixbits.append(0) pixbits.append(0) self.comb += memory_word.eq(Cat(*pixbits)) # bus accessor self.submodules._bus_accessor = dma_lasmi.Writer(lasmim) self.comb += [ self._bus_accessor.address_data.payload.a.eq(current_address), self._bus_accessor.address_data.payload.d.eq(memory_word) ] # control FSM fsm = FSM() self.submodules += fsm fsm.act("WAIT_SOF", reset_words.eq(1), self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.payload.sof), If(self._slot_array.address_valid & self.frame.payload.sof & self.frame.stb, NextState("TRANSFER_PIXELS")) ) fsm.act("TRANSFER_PIXELS", self.frame.ack.eq(self._bus_accessor.address_data.ack), If(self.frame.stb, self._bus_accessor.address_data.stb.eq(1), If(self._bus_accessor.address_data.ack, count_word.eq(1), If(last_word, NextState("EOF")) ) ) ) fsm.act("EOF", If(~self._bus_accessor.busy, self._slot_array.address_done.eq(1), NextState("WAIT_SOF") ) )
def __init__(self, pads, default=_default_edid): self.specials.mem = Memory(8, 128, init=default) ### scl_raw = Signal() sda_i = Signal() sda_drv = Signal() _sda_drv_reg = Signal() _sda_i_async = Signal() self.sync += _sda_drv_reg.eq(sda_drv) self.specials += [ MultiReg(pads.scl, scl_raw), Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async), MultiReg(_sda_i_async, sda_i) ] scl_i = Signal() samp_count = Signal(6) samp_carry = Signal() self.sync += [ Cat(samp_count, samp_carry).eq(samp_count + 1), If(samp_carry, scl_i.eq(scl_raw)) ] scl_r = Signal() sda_r = Signal() scl_rising = Signal() sda_rising = Signal() sda_falling = Signal() self.sync += [ scl_r.eq(scl_i), sda_r.eq(sda_i) ] self.comb += [ scl_rising.eq(scl_i & ~scl_r), sda_rising.eq(sda_i & ~sda_r), sda_falling.eq(~sda_i & sda_r) ] start = Signal() self.comb += start.eq(scl_i & sda_falling) din = Signal(8) counter = Signal(max=9) self.sync += [ If(start, counter.eq(0)), If(scl_rising, If(counter == 8, counter.eq(0) ).Else( counter.eq(counter + 1), din.eq(Cat(sda_i, din[:7])) ) ) ] is_read = Signal() update_is_read = Signal() self.sync += If(update_is_read, is_read.eq(din[0])) offset_counter = Signal(max=128) oc_load = Signal() oc_inc = Signal() self.sync += [ If(oc_load, offset_counter.eq(din) ).Elif(oc_inc, offset_counter.eq(offset_counter + 1) ) ] rdport = self.mem.get_port() self.comb += rdport.adr.eq(offset_counter) data_bit = Signal() zero_drv = Signal() data_drv = Signal() self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit)) data_drv_en = Signal() data_drv_stop = Signal() self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0)) self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True)) states = ["WAIT_START", "RCV_ADDRESS", "ACK_ADDRESS0", "ACK_ADDRESS1", "ACK_ADDRESS2", "RCV_OFFSET", "ACK_OFFSET0", "ACK_OFFSET1", "ACK_OFFSET2", "READ", "ACK_READ"] fsm = FSM(*states) self.submodules += fsm fsm.act(fsm.RCV_ADDRESS, If(counter == 8, If(din[1:] == 0x50, update_is_read.eq(1), fsm.next_state(fsm.ACK_ADDRESS0) ).Else( fsm.next_state(fsm.WAIT_START) ) ) ) fsm.act(fsm.ACK_ADDRESS0, If(~scl_i, fsm.next_state(fsm.ACK_ADDRESS1)) ) fsm.act(fsm.ACK_ADDRESS1, zero_drv.eq(1), If(scl_i, fsm.next_state(fsm.ACK_ADDRESS2)) ) fsm.act(fsm.ACK_ADDRESS2, zero_drv.eq(1), If(~scl_i, If(is_read, fsm.next_state(fsm.READ) ).Else( fsm.next_state(fsm.RCV_OFFSET) ) ) ) fsm.act(fsm.RCV_OFFSET, If(counter == 8, oc_load.eq(1), fsm.next_state(fsm.ACK_OFFSET0) ) ) fsm.act(fsm.ACK_OFFSET0, If(~scl_i, fsm.next_state(fsm.ACK_OFFSET1)) ) fsm.act(fsm.ACK_OFFSET1, zero_drv.eq(1), If(scl_i, fsm.next_state(fsm.ACK_OFFSET2)) ) fsm.act(fsm.ACK_OFFSET2, zero_drv.eq(1), If(~scl_i, fsm.next_state(fsm.RCV_ADDRESS)) ) fsm.act(fsm.READ, If(~scl_i, If(counter == 8, data_drv_stop.eq(1), fsm.next_state(fsm.ACK_READ) ).Else( data_drv_en.eq(1) ) ) ) fsm.act(fsm.ACK_READ, If(scl_rising, oc_inc.eq(1), If(sda_i, fsm.next_state(fsm.WAIT_START) ).Else( fsm.next_state(fsm.READ) ) ) ) for state in states: fsm.act(getattr(fsm, state), If(start, fsm.next_state(fsm.RCV_ADDRESS)))
def __init__(self, ulpi, ulpi_reg): ulpi_data_out = Signal(8) ulpi_data_tristate = Signal() ulpi_data_next = Signal(8) ulpi_data_tristate_next = Signal() ulpi_stp_next = Signal() ulpi_state_rx = Signal() ulpi_state_rrd = Signal() self.data_out_source = Source(ULPI_DATA) RegWriteReqR = Signal() RegReadReqR = Signal() RegWriteReq = Signal() RegReadReq = Signal() RegReadAckSet = Signal() RegWriteAckSet = Signal() # register the reg read/write requests self.sync += RegReadReqR.eq(ulpi_reg.rreq) self.sync += RegWriteReqR.eq(ulpi_reg.wreq) # signal when read/write is requested but not done self.comb += RegReadReq.eq(RegReadReqR & ~ulpi_reg.rack) v = (RegReadReqR & ~ulpi_reg.rack) self.comb += RegWriteReq.eq(RegWriteReqR & ~ulpi_reg.wack) # ack logic: set ack=0 when req=0, set ack=1 when access done self.sync += If(~RegReadReqR, ulpi_reg.rack.eq(0) ).Elif(RegReadAckSet, ulpi_reg.rack.eq(1)) self.sync += If(~RegWriteReqR, ulpi_reg.wack.eq(0) ).Elif(RegWriteAckSet, ulpi_reg.wack.eq(1)) exp = If(~RegWriteReqR, ulpi_reg.wack.eq(0)).Elif(RegWriteAckSet, ulpi_reg.wack.eq(1)) # output data if required by state self.comb += ulpi.stp.eq(ulpi_stp_next) self.comb += ulpi_data_out.eq(ulpi_data_next) self.comb += ulpi_data_tristate.eq(ulpi_data_tristate_next) self.comb += ulpi.do.eq(ulpi_data_out) self.comb += ulpi.doe.eq(~ulpi_data_tristate) # capture RX data at the end of RX, but only if no turnaround was requested # We also support "stuffing" data, to indicate conditions such as: # - Simultaneous DIR + NXT assertion # (the spec doesn't require an RXCMD - DIR+NXT asserting may be the' # only SOP signal) # - End-of-packet # (Packets may end without an RXCMD, unless an error occurs) ulpi_rx_stuff = Signal() ulpi_rx_stuff_d = Signal(8) self.sync += self.data_out_source.stb.eq(ulpi_state_rx & ulpi.dir | ulpi_rx_stuff) self.sync += If(ulpi_rx_stuff, self.data_out_source.payload.d.eq(ulpi_rx_stuff_d), self.data_out_source.payload.rxcmd.eq(1) ).Else( If(~ulpi.nxt, self.data_out_source.payload.d.eq(ulpi.di & RXCMD_MASK), self.data_out_source.payload.rxcmd.eq(1) ).Else( self.data_out_source.payload.d.eq(ulpi.di), self.data_out_source.payload.rxcmd.eq(0) ) ) # capture register reads at the end of RRD self.sync += If(ulpi_state_rrd,ulpi_reg.rdata.eq(ulpi.di)) fsm = FSM() self.submodules += fsm fsm.act("IDLE", ulpi_data_next.eq(0x00), # NOOP ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0), If(~ulpi.dir & ~ulpi.nxt & ~(RegWriteReq | RegReadReq), NextState("IDLE") ).Elif(ulpi.dir, # TA, and then either RXCMD or Data NextState("RX"), ulpi_data_tristate_next.eq(1), # If dir & nxt, we're starting a packet, so stuff a custom SOP If(ulpi.nxt, ulpi_rx_stuff.eq(1), ulpi_rx_stuff_d.eq(RXCMD_MAGIC_SOP) ) ).Elif(RegWriteReq, NextState("RW0"), ulpi_data_next.eq(0x80 | ulpi_reg.waddr), # REGW ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0) ).Elif(RegReadReq, NextState("RR0"), ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0) ).Else( NextState("ERROR") )) fsm.act("RX", If(ulpi.dir, # stay in RX NextState("RX"), ulpi_state_rx.eq(1), ulpi_data_tristate_next.eq(1) ).Else( # TA back to idle # Stuff an EOP on return to idle ulpi_rx_stuff.eq(1), ulpi_rx_stuff_d.eq(RXCMD_MAGIC_EOP), ulpi_data_tristate_next.eq(0), NextState("IDLE") )) fsm.act("RW0", If(ulpi.dir, NextState("RX"), ulpi_data_tristate_next.eq(1), ).Elif(~ulpi.dir, ulpi_data_next.eq(0x80 | ulpi_reg.waddr), # REGW ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0), If(ulpi.nxt, NextState("RWD")).Else(NextState("RW0")), ).Else( NextState("ERROR") )) fsm.act("RWD", If(ulpi.dir, NextState("RX"), ulpi_data_tristate_next.eq(1) ).Elif(~ulpi.dir & ulpi.nxt, NextState("RWS"), ulpi_data_next.eq(ulpi_reg.wdata), ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(0) ).Else( NextState("ERROR") ), ) fsm.act("RWS", If(~ulpi.dir, NextState("IDLE"), ulpi_data_next.eq(0x00), # NOOP ulpi_data_tristate_next.eq(0), ulpi_stp_next.eq(1), RegWriteAckSet.eq(1) ).Elif(ulpi.dir, NextState("RX"), ulpi_data_tristate_next.eq(1), ), ) fsm.act("RR0", If(~ulpi.dir, ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR NextState("RR1") ).Elif(ulpi.dir, NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") )) fsm.act("RR1", If(~ulpi.dir & ulpi.nxt, # PHY accepts REGR ulpi_data_tristate_next.eq(1), # TA NextState("RR2") ).Elif(~ulpi.dir & ~ulpi.nxt, # PHY delays REGR ulpi_data_next.eq(0xC0 | ulpi_reg.raddr), # REGR NextState("RR1") ).Elif(ulpi.dir, NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") )) fsm.act("RR2", ulpi_data_tristate_next.eq(1), If(~ulpi.nxt, # REGR continue NextState("RRD") ).Elif(ulpi.dir, # PHY indicates RX NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") )) fsm.act("RRD", If(ulpi.dir & ~ulpi.nxt, NextState("IDLE"), RegReadAckSet.eq(1), ulpi_state_rrd.eq(1), ).Elif(ulpi.dir & ulpi.nxt, NextState("RX"), RegWriteAckSet.eq(1) ).Else( NextState("ERROR") ), ulpi_data_tristate_next.eq(1), ) fsm.act("ERROR", NextState("IDLE"))
from migen.fhdl.structure import * from migen.fhdl import verilog from migen.genlib.fsm import FSM s = Signal() myfsm = FSM("FOO", "BAR") myfsm.act(myfsm.FOO, s.eq(1), myfsm.next_state(myfsm.BAR)) myfsm.act(myfsm.BAR, s.eq(0), myfsm.next_state(myfsm.FOO)) print(verilog.convert(myfsm.get_fragment(), {s}))
def __init__(self, sys_clk_freq, rx, mode="single"): assert isinstance(rx, bool) assert mode in ["single", "master", "slave"] self.mode = mode self.done = Signal() self.restart = Signal() # GTX signals self.cplllock = Signal() self.cpllreset = Signal() self.gtXxreset = Signal() self.Xxresetdone = Signal() self.Xxdlysreset = Signal() self.Xxdlysresetdone = Signal() self.Xxphaligndone = Signal() self.Xxuserrdy = Signal() # GTX signals exclusive to multi-lane if mode != "single": self.Xxphalign = Signal() self.Xxdlyen = Signal() # TX only: if not rx: self.txphinit = Signal() self.txphinitdone = Signal() # Strobe from master channel to initialize TX/RX phase alignment on slaves self.master_phaligndone = Signal() # Strobe from slave channels to re-enable TX/RX delay alignment on master; # To be combinatorially AND-ed from all slave's `done` if mode == "master": self.slaves_phaligndone = Signal() # # # # Double-latch transceiver asynch outputs cplllock = Signal() Xxresetdone = Signal() Xxdlysresetdone = Signal() Xxphaligndone = Signal() self.specials += [ MultiReg(self.cplllock, cplllock), MultiReg(self.Xxresetdone, Xxresetdone), MultiReg(self.Xxdlysresetdone, Xxdlysresetdone), MultiReg(self.Xxphaligndone, Xxphaligndone), ] if mode != "single": txphinitdone = Signal() self.specials += MultiReg(self.txphinitdone, txphinitdone) # Deglitch FSM outputs driving transceiver asynch inputs gtXxreset = Signal() Xxdlysreset = Signal() Xxuserrdy = Signal() self.sync += [ self.gtXxreset.eq(gtXxreset), self.Xxdlysreset.eq(Xxdlysreset), self.Xxuserrdy.eq(Xxuserrdy) ] if mode != "single": Xxphalign = Signal() Xxdlyen = Signal() self.sync += [ self.Xxphalign.eq(Xxphalign), self.Xxdlyen.eq(Xxdlyen) ] if not rx: txphinit = Signal() self.sync += self.txphinit.eq(txphinit) # After configuration, transceiver resets have to stay low for # at least 500ns (see AR43482) startup_cycles = ceil(500*sys_clk_freq/1000000000) startup_timer = WaitTimer(startup_cycles) self.submodules += startup_timer # PLL reset should be 1 period of refclk # (i.e. 1/(125MHz) for the case of RTIO @ 125MHz) pll_reset_cycles = ceil(sys_clk_freq/125e6) pll_reset_timer = WaitTimer(pll_reset_cycles) self.submodules += pll_reset_timer startup_fsm = FSM(reset_state="INITIAL") self.submodules += startup_fsm if rx: cdr_stable_timer = WaitTimer(1024) self.submodules += cdr_stable_timer # Rising edge detection for phase alignment "done" Xxphaligndone_r = Signal(reset=1) Xxphaligndone_rising = Signal() self.sync += Xxphaligndone_r.eq(Xxphaligndone) self.comb += Xxphaligndone_rising.eq(Xxphaligndone & ~Xxphaligndone_r) startup_fsm.act("INITIAL", startup_timer.wait.eq(1), If(startup_timer.done, NextState("RESET_ALL")) ) startup_fsm.act("RESET_ALL", gtXxreset.eq(1), self.cpllreset.eq(1), pll_reset_timer.wait.eq(1), If(pll_reset_timer.done, NextState("RELEASE_PLL_RESET")) ) startup_fsm.act("RELEASE_PLL_RESET", gtXxreset.eq(1), If(cplllock, NextState("RELEASE_GTH_RESET")) ) # Release GTX reset and wait for GTX resetdone # (from UG476, GTX is reset on falling edge # of gttxreset) if rx: startup_fsm.act("RELEASE_GTH_RESET", Xxuserrdy.eq(1), cdr_stable_timer.wait.eq(1), If(Xxresetdone & cdr_stable_timer.done, NextState("DELAY_ALIGN")) ) else: startup_fsm.act("RELEASE_GTH_RESET", Xxuserrdy.eq(1), If(Xxresetdone, NextState("DELAY_ALIGN")) ) # States exclusive to Auto Mode: if mode == "single": # Start delay alignment (pulse) startup_fsm.act("DELAY_ALIGN", Xxuserrdy.eq(1), Xxdlysreset.eq(1), NextState("WAIT_DELAY_ALIGN") ) # Wait for delay alignment startup_fsm.act("WAIT_DELAY_ALIGN", Xxuserrdy.eq(1), If(Xxdlysresetdone, NextState("WAIT_FIRST_PHASE_ALIGN_DONE")) ) # Wait 2 rising edges of rxphaligndone # (from UG476 in buffer bypass config) startup_fsm.act("WAIT_FIRST_PHASE_ALIGN_DONE", Xxuserrdy.eq(1), If(Xxphaligndone_rising, NextState("WAIT_SECOND_PHASE_ALIGN_DONE")) ) startup_fsm.act("WAIT_SECOND_PHASE_ALIGN_DONE", Xxuserrdy.eq(1), If(Xxphaligndone_rising, NextState("READY")) ) # States exclusive to Manual Mode: else: # Start delay alignment (hold) startup_fsm.act("DELAY_ALIGN", Xxuserrdy.eq(1), Xxdlysreset.eq(1), If(Xxdlysresetdone, # TX master: proceed to initialize phase alignment manually (NextState("PHASE_ALIGN_INIT") if not rx else # RX master: proceed to start phase alignment manually NextState("PHASE_ALIGN")) if mode == "master" else # TX/RX slave: wait for phase alignment "done" on master NextState("WAIT_MASTER") ) ) if mode == "slave": # TX slave: Wait for phase alignment "done" on master startup_fsm.act("WAIT_MASTER", Xxuserrdy.eq(1), If(self.master_phaligndone, # TX slave: proceed to initialize phase alignment manually NextState("PHASE_ALIGN_INIT") if not rx else # RX slave: proceed to start phase alignment manually NextState("PHASE_ALIGN") ) ) if not rx: # TX master/slave: Initialize phase alignment, wait rising edge on "done" startup_fsm.act("PHASE_ALIGN_INIT", Xxuserrdy.eq(1), txphinit.eq(1), If(txphinitdone, NextState("PHASE_ALIGN")) ) # Do phase ealignment, wait rising edge on "done" startup_fsm.act("PHASE_ALIGN", Xxuserrdy.eq(1), Xxphalign.eq(1), If(Xxphaligndone_rising, # TX/RX master: proceed to set T/RXDLYEN NextState("FIRST_DLYEN") if mode == "master" else # TX/RX slave: proceed to signal master NextState("READY") ) ) if mode == "master": # Enable delay alignment in manual mode, wait rising edge on phase alignment "done" startup_fsm.act("FIRST_DLYEN", Xxuserrdy.eq(1), Xxdlyen.eq(1), If(Xxphaligndone_rising, NextState("WAIT_SLAVES")) ) # Wait for phase alignment "done" on all slaves startup_fsm.act("WAIT_SLAVES", Xxuserrdy.eq(1), self.master_phaligndone.eq(1), If(self.slaves_phaligndone, NextState("SECOND_DLYEN")) ) # Re-enable delay alignment in manual mode, wait rising edge on phase alignment "done" startup_fsm.act("SECOND_DLYEN", Xxuserrdy.eq(1), Xxdlyen.eq(1), If(Xxphaligndone_rising, NextState("READY")) ) # Transceiver is ready, alignment can be restarted startup_fsm.act("READY", Xxuserrdy.eq(1), self.done.eq(1), If(self.restart, NextState("RESET_ALL")) )
def __init__(self, dram_port, nslots): bus_aw = dram_port.aw bus_dw = dram_port.dw alignment_bits = bits_for(bus_dw // 8) - 1 fifo_word_width = bus_dw self.frame = stream.Endpoint([("sof", 1), ("pixels", fifo_word_width)]) self._frame_size = CSRStorage(bus_aw + alignment_bits) self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits) self.ev = self._slot_array.ev # # # # address generator + maximum memory word count to prevent DMA buffer # overrun reset_words = Signal() count_word = Signal() last_word = Signal() current_address = Signal(bus_aw) mwords_remaining = Signal(bus_aw) self.comb += [ self._slot_array.address_reached.eq(current_address), last_word.eq(mwords_remaining == 1) ] self.sync += [ If(reset_words, current_address.eq(self._slot_array.address), mwords_remaining.eq( self._frame_size.storage[alignment_bits:])).Elif( count_word, current_address.eq(current_address + 1), mwords_remaining.eq(mwords_remaining - 1)) ] memory_word = Signal(bus_dw) pixbits = [] for i in range(bus_dw // 16): pixbits.append(self.frame.pixels) self.comb += memory_word.eq(Cat(*pixbits)) # bus accessor self.submodules._bus_accessor = LiteDRAMDMAWriter(dram_port) self.comb += [ self._bus_accessor.sink.address.eq(current_address), self._bus_accessor.sink.data.eq(memory_word) ] # control FSM fsm = FSM() self.submodules += fsm fsm.act( "WAIT_SOF", reset_words.eq(1), self.frame.ready.eq(~self._slot_array.address_valid | ~self.frame.sof), If( self._slot_array.address_valid & self.frame.sof & self.frame.valid, NextState("TRANSFER_PIXELS"))) fsm.act( "TRANSFER_PIXELS", self.frame.ready.eq(self._bus_accessor.sink.ready), If( self.frame.valid, self._bus_accessor.sink.valid.eq(1), If(self._bus_accessor.sink.ready, count_word.eq(1), If(last_word, NextState("EOF"))))) fsm.act( "EOF", If(~dram_port.wdata.valid, self._slot_array.address_done.eq(1), NextState("WAIT_SOF")))
def __init__(self, a, ba, tRP, tREFI, tRFC): self.req = Signal() self.ack = Signal() # 1st command 1 cycle after assertion of ack self.cmd = CommandRequest(a, ba) ### # Refresh sequence generator: # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done seq_start = Signal() seq_done = Signal() self.sync += [ self.cmd.a.eq(2**10), self.cmd.ba.eq(0), self.cmd.cas_n.eq(1), self.cmd.ras_n.eq(1), self.cmd.we_n.eq(1), seq_done.eq(0) ] self.sync += timeline(seq_start, [ (1, [ self.cmd.ras_n.eq(0), self.cmd.we_n.eq(0) ]), (1+tRP, [ self.cmd.cas_n.eq(0), self.cmd.ras_n.eq(0) ]), (1+tRP+tRFC, [ seq_done.eq(1) ]) ]) # Periodic refresh counter counter = Signal(max=tREFI) start = Signal() self.sync += [ start.eq(0), If(counter == 0, start.eq(1), counter.eq(tREFI - 1) ).Else( counter.eq(counter - 1) ) ] # Control FSM fsm = FSM() self.submodules += fsm fsm.act("IDLE", If(start, NextState("WAIT_GRANT"))) fsm.act("WAIT_GRANT", self.req.eq(1), If(self.ack, seq_start.eq(1), NextState("WAIT_SEQ") ) ) fsm.act("WAIT_SEQ", self.req.eq(1), If(seq_done, NextState("IDLE")) )
def __init__(self, platform): super().__init__(platform) # Internal registers. self.address_reg = Signal(32) self.data_reg = Signal(32) # Wishbone signals. self.wishbone_adr_o = Signal(32) self.wishbone_dat_o = Signal(32) self.wishbone_dat_i = Signal(32) self.wishbone_ack_i = Signal() self.wishbone_cyc_o = Signal() self.wishbone_err_i = Signal() self.wishbone_rty_i = Signal() self.wishbone_sel_o = Signal() self.wishbone_stb_o = Signal() self.wishbone_we_o = Signal() # The wishbone address is always whatever we're given in the # address register. self.comb += [self.wishbone_adr_o.eq(self.address_reg)] # Rule is that a write to the MSB of the data triggers a write, # and a read from the LSB of the data triggers a read. The other # bits of the data are not affected until those actions take place. # Bear in mind that 6502s have a bad habit of double-reads with # some instructions, and so care must be taken not to accidentally # read twice! # Layout of our registers is just DATA, ADDRESS, sequentially as # bytes in 6502-space. is_read_to_lsb = self.cs & (self.address == 0x00) & ~self.we is_write_to_msb = self.cs & (self.address == 0x03) & self.we # Regardless of what else you do, we always read/write from the # relevant registers. Because we're given CS early this can be # sync. self.sync += [ Case( self.address, { 0: self.data_out.eq(self.data_reg[0]), 1: self.data_out.eq(self.data_reg[1]), 2: self.data_out.eq(self.data_reg[2]), 3: self.data_out.eq(self.data_reg[3]), 4: self.data_out.eq(self.address_reg[0]), 5: self.data_out.eq(self.address_reg[1]), 6: self.data_out.eq(self.address_reg[2]), 7: self.data_out.eq(self.address_reg[3]) }) ] # FSM to manage interaction with wishbone. sm = FSM(reset_state="RESET") self.submodules += sm sm.act("RESET", NextValue(self.wishbone_cyc_o, False), NextValue(self.wishbone_stb_o, False), NextValue(self.nmi, False), NextState("IDLE")) sm.act("IDLE", If(is_read_to_lsb, NextState("START_READ")), If(is_write_to_msb, NextState("START_WRITE"))) sm.act( "START_READ", NextValue(self.rdy, False), # Pause the 6502. NextValue(self.wishbone_cyc_o, True), # Start the wishbone cycle. NextValue(self.wishbone_stb_o, True), # Trigger the strobe NextValue(self.wishbone_we_o, False), # We're reading. If(self.wishbone_ack_i, NextState("READ_COMPLETE")), If(self.wishbone_rty_i | self.wishbone_err_i, NextValue(self.nmi, True), NextState("RESET"))) sm.act( "READ_COMPLETE", NextValue(self.rdy, True), # Let the 6502 know we're done. NextValue(self.wishbone_cyc_o, False), # Wishbone cycle complete. NextValue(self.wishbone_stb_o, False), # Strobe low too. NextValue(self.data_reg, self.wishbone_dat_i), # Save the read data. NextState("IDLE")) sm.act( "START_WRITE", NextValue(self.rdy, False), # Tell the 6502 to wait. NextValue(self.wishbone_cyc_o, True), # Start the wishbone cycle. NextValue(self.wishbone_stb_o, True), # Strobe active too. NextValue(self.wishbone_dat_o, self.data_reg), # Send the data. If(self.wishbone_ack_i, NextState("WRITE_COMPLETE")), If(self.wishbone_rty_i | self.wishbone_err_i, NextValue(self.nmi, True), NextState("RESET"))) sm.act( "WRITE_COMPLETE", NextValue(self.rdy, True), # Let the 6502 know we're done NextValue(self.wishbone_cyc_o, False), # Wishbone cycle complete NextValue(self.wishbone_stb_o, False), # Strobe complete. NextState("IDLE"))
def __init__(self): self.arb_req = CSRStorage() self.arb_gnt = CSRStatus() self.error_status = CSRStatus(5) # same encoding as RTIO status self.error_underflow_reset = CSR() self.error_sequence_error_reset = CSR() self.error_collision_reset = CSR() self.error_busy_reset = CSR() self.error_channel = CSRStatus(24) self.error_timestamp = CSRStatus(64) self.error_address = CSRStatus(16) self.sink = stream.Endpoint(record_layout) self.cri = cri.Interface() self.busy = Signal() # # # self.comb += [ self.cri.arb_req.eq(self.arb_req.storage), self.arb_gnt.status.eq(self.cri.arb_gnt) ] error_set = Signal(4) for i, rcsr in enumerate([ self.error_underflow_reset, self.error_sequence_error_reset, self.error_collision_reset, self.error_busy_reset ]): # bit 0 is RTIO wait and always 0 here bit = i + 1 self.sync += [ If(error_set[i], self.error_status.status[bit].eq(1), self.error_channel.status.eq(self.sink.channel), self.error_timestamp.status.eq(self.sink.timestamp), self.error_address.status.eq(self.sink.address)), If(rcsr.re, self.error_status.status[bit].eq(0)) ] self.comb += [ self.cri.chan_sel.eq(self.sink.channel), self.cri.o_timestamp.eq(self.sink.timestamp), self.cri.o_address.eq(self.sink.address), self.cri.o_data.eq(self.sink.data) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act( "IDLE", If( self.error_status.status == 0, If( self.sink.stb, If( self.sink.eop, # last packet contains dummy data, discard it self.sink.ack.eq(1)).Else(NextState("WRITE")))).Else( # discard all data until errors are acked self.sink.ack.eq(1))) fsm.act("WRITE", self.busy.eq(1), self.cri.cmd.eq(cri.commands["write"]), NextState("CHECK_STATE")) fsm.act( "CHECK_STATE", self.busy.eq(1), If(self.cri.o_status == 0, self.sink.ack.eq(1), NextState("IDLE")), If(self.cri.o_status[1], NextState("UNDERFLOW")), If(self.cri.o_status[2], NextState("SEQUENCE_ERROR")), If(self.cri.o_status[3], NextState("COLLISION")), If(self.cri.o_status[4], NextState("BUSY"))) for n, name in enumerate( ["UNDERFLOW", "SEQUENCE_ERROR", "COLLISION", "BUSY"]): fsm.act( name, self.busy.eq(1), error_set.eq(1 << n), self.cri.cmd.eq(cri.commands["o_" + name.lower() + "_reset"]), self.sink.ack.eq(1), NextState("IDLE"))
def __init__(self, lasmim, nslots): bus_aw = lasmim.aw bus_dw = lasmim.dw alignment_bits = bits_for(bus_dw//8) - 1 # debug print("LASMI Bus Address Width : {}".format(bus_aw)) print("LASMI Bus Data Width : {}".format(bus_dw)) fifo_word_width = bus_dw self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)]) self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits) self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits) self.ev = self._slot_array.ev ### # address generator + maximum memory word count to prevent DMA buffer overrun reset_words = Signal() count_word = Signal() last_word = Signal() current_address = Signal(bus_aw) mwords_remaining = Signal(bus_aw) self.comb += [ self._slot_array.address_reached.eq(current_address), last_word.eq(mwords_remaining == 1) ] self.sync += [ If(reset_words, current_address.eq(self._slot_array.address), mwords_remaining.eq(self._frame_size.storage) #Initially there was no division by 4 ).Elif(count_word, current_address.eq(current_address + 1), mwords_remaining.eq(mwords_remaining - 1) ) ] memory_word = Signal(bus_dw) pixbits = [] for i in range(bus_dw//16): #was initially 16 pixbits.append(self.frame.pixels) self.comb += memory_word.eq(Cat(*pixbits)) # bus accessor self.submodules._bus_accessor = dma_lasmi.Writer(lasmim) self.comb += [ self._bus_accessor.address_data.a.eq(current_address), self._bus_accessor.address_data.d.eq(memory_word) ] # control FSM fsm = FSM() self.submodules += fsm fsm.act("WAIT_SOF", reset_words.eq(1), self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.sof), If(self._slot_array.address_valid & self.frame.sof & self.frame.stb, NextState("TRANSFER_PIXELS")) ) fsm.act("TRANSFER_PIXELS", self.frame.ack.eq(self._bus_accessor.address_data.ack), If(self.frame.stb, self._bus_accessor.address_data.stb.eq(1), If(self._bus_accessor.address_data.ack, count_word.eq(1), If(last_word, NextState("EOF")) ) ) ) fsm.act("EOF", If(~self._bus_accessor.busy, self._slot_array.address_done.eq(1), NextState("WAIT_SOF") ) )
def __init__(self, dw_i, dw_o): self.wishbone_i = Interface(dw_i) self.wishbone_o = Interface(dw_o) self.ratio = dw_i//dw_o ### rst = Signal() # generate internal write and read ack write_ack = Signal() read_ack = Signal() ack = Signal() self.comb += [ ack.eq(self.wishbone_o.cyc & self.wishbone_o.stb & self.wishbone_o.ack), write_ack.eq(ack & self.wishbone_o.we), read_ack.eq(ack & ~self.wishbone_o.we) ] # accesses counter logic cnt = Signal(max=self.ratio) self.sync += If(rst, cnt.eq(0)).Elif(ack, cnt.eq(cnt + 1)) # read data path dat_r = Signal(dw_i) self.sync += If(ack, dat_r.eq(Cat(self.wishbone_o.dat_r, dat_r[:dw_i-dw_o]))) # write data path dat_w = Signal(dw_i) self.comb += dat_w.eq(self.wishbone_i.dat_w) # errors generation err = Signal() self.sync += If(ack, err.eq(self.wishbone_o.err)) # direct connection of wishbone_i --> wishbone_o signals for name, size, direction in self.wishbone_i.layout: if direction == DIR_M_TO_S and name not in ["adr", "dat_w"]: self.comb += getattr(self.wishbone_o, name).eq(getattr(self.wishbone_i, name)) # adaptation of adr & dat signals self.comb += [ self.wishbone_o.adr[0:flen(cnt)].eq(cnt), self.wishbone_o.adr[flen(cnt):].eq(self.wishbone_i.adr) ] self.comb += chooser(dat_w, cnt, self.wishbone_o.dat_w, reverse=True) # fsm fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", If(write_ack, NextState("WRITE_ADAPT")), If(read_ack, NextState("READ_ADAPT")) ) fsm.act("WRITE_ADAPT", If(write_ack & (cnt == self.ratio-1), NextState("IDLE"), rst.eq(1), self.wishbone_i.err.eq(err | self.wishbone_o.err), self.wishbone_i.ack.eq(1), ) ) master_i_dat_r = Signal(dw_i) self.comb += master_i_dat_r.eq(Cat(self.wishbone_o.dat_r, dat_r[:dw_i-dw_o])) fsm.act("READ_ADAPT", If(read_ack & (cnt == self.ratio-1), NextState("IDLE"), rst.eq(1), self.wishbone_i.err.eq(err | self.wishbone_o.err), self.wishbone_i.ack.eq(1), self.wishbone_i.dat_r.eq(master_i_dat_r) ) )
def __init__(self): self.s = Signal() myfsm = FSM("FOO", "BAR") self.submodules += myfsm myfsm.act(myfsm.FOO, self.s.eq(1), myfsm.next_state(myfsm.BAR)) myfsm.act(myfsm.BAR, self.s.eq(0), myfsm.next_state(myfsm.FOO))
def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, lasmic): assert(phy_settings.nphases == len(dfi.phases)) # Command choosing requests = [bm.cmd for bm in bank_machines] choose_cmd = _CommandChooser(requests) choose_req = _CommandChooser(requests) self.comb += [ choose_cmd.want_reads.eq(0), choose_cmd.want_writes.eq(0) ] if phy_settings.nphases == 1: self.comb += [ choose_cmd.want_cmds.eq(1), choose_req.want_cmds.eq(1) ] self.submodules += choose_cmd, choose_req # Command steering nop = CommandRequest(geom_settings.mux_a, geom_settings.bank_a) commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st (STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4) steerer = _Steerer(commands, dfi) self.submodules += steerer # Read/write turnaround read_available = Signal() write_available = Signal() self.comb += [ read_available.eq(optree("|", [req.stb & req.is_read for req in requests])), write_available.eq(optree("|", [req.stb & req.is_write for req in requests])) ] def anti_starvation(timeout): en = Signal() max_time = Signal() if timeout: t = timeout - 1 time = Signal(max=t+1) self.comb += max_time.eq(time == 0) self.sync += If(~en, time.eq(t) ).Elif(~max_time, time.eq(time - 1) ) else: self.comb += max_time.eq(0) return en, max_time read_time_en, max_read_time = anti_starvation(timing_settings.read_time) write_time_en, max_write_time = anti_starvation(timing_settings.write_time) # Refresh self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines] go_to_refresh = Signal() self.comb += go_to_refresh.eq(optree("&", [bm.refresh_gnt for bm in bank_machines])) # Datapath all_rddata = [p.rddata for p in dfi.phases] all_wrdata = [p.wrdata for p in dfi.phases] all_wrdata_mask = [p.wrdata_mask for p in dfi.phases] self.comb += [ lasmic.dat_r.eq(Cat(*all_rddata)), Cat(*all_wrdata).eq(lasmic.dat_w), Cat(*all_wrdata_mask).eq(~lasmic.dat_we) ] # Control FSM fsm = FSM() self.submodules += fsm def steerer_sel(steerer, phy_settings, r_w_n): r = [] for i in range(phy_settings.nphases): s = steerer.sel[i].eq(STEER_NOP) if r_w_n == "read": if i == phy_settings.rdphase: s = steerer.sel[i].eq(STEER_REQ) elif i == phy_settings.rdcmdphase: s = steerer.sel[i].eq(STEER_CMD) elif r_w_n == "write": if i == phy_settings.wrphase: s = steerer.sel[i].eq(STEER_REQ) elif i == phy_settings.wrcmdphase: s = steerer.sel[i].eq(STEER_CMD) else: raise ValueError r.append(s) return r fsm.act("READ", read_time_en.eq(1), choose_req.want_reads.eq(1), choose_cmd.cmd.ack.eq(1), choose_req.cmd.ack.eq(1), steerer_sel(steerer, phy_settings, "read"), If(write_available, # TODO: switch only after several cycles of ~read_available? If(~read_available | max_read_time, NextState("RTW")) ), If(go_to_refresh, NextState("REFRESH")) ) fsm.act("WRITE", write_time_en.eq(1), choose_req.want_writes.eq(1), choose_cmd.cmd.ack.eq(1), choose_req.cmd.ack.eq(1), steerer_sel(steerer, phy_settings, "write"), If(read_available, If(~write_available | max_write_time, NextState("WTR")) ), If(go_to_refresh, NextState("REFRESH")) ) fsm.act("REFRESH", steerer.sel[0].eq(STEER_REFRESH), If(~refresher.req, NextState("READ")) ) fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1) # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog fsm.finalize() self.comb += refresher.ack.eq(fsm.state == fsm.encoding["REFRESH"]) self.submodules.bandwidth = Bandwidth(choose_req.cmd)
def __init__(self, clock_pads, pads): self._reset = CSRStorage() # # # self.clock_domains.cd_eth_rx = ClockDomain() self.clock_domains.cd_eth_tx = ClockDomain() # RX dcm_reset = Signal() dcm_locked = Signal() timer = WaitTimer(1024) fsm = FSM(reset_state="DCM_RESET") self.submodules += timer, fsm fsm.act("DCM_RESET", dcm_reset.eq(1), timer.wait.eq(1), If(timer.done, timer.wait.eq(0), NextState("DCM_WAIT") ) ) fsm.act("DCM_WAIT", timer.wait.eq(1), If(timer.done, NextState("DCM_CHECK_LOCK") ) ) fsm.act("DCM_CHECK_LOCK", If(~dcm_locked, NextState("DCM_RESET") ) ) clk90_rx = Signal() clk0_rx = Signal() clk0_rx_bufg = Signal() self.specials += Instance("DCM", i_CLKIN=clock_pads.rx, i_CLKFB=clk0_rx_bufg, o_CLK0=clk0_rx, o_CLK90=clk90_rx, o_LOCKED=dcm_locked, i_PSEN=0, i_PSCLK=0, i_PSINCDEC=0, i_RST=dcm_reset ) self.specials += Instance("BUFG", i_I=clk0_rx, o_O=clk0_rx_bufg) self.specials += Instance("BUFG", i_I=clk90_rx, o_O=self.cd_eth_rx.clk) # TX self.specials += DDROutput(1, 0, clock_pads.tx, ClockSignal("eth_tx")) self.specials += Instance("BUFG", i_I=self.cd_eth_rx.clk, o_O=self.cd_eth_tx.clk) # Reset reset = self._reset.storage self.comb += pads.rst_n.eq(~reset) self.specials += [ AsyncResetSynchronizer(self.cd_eth_tx, reset), AsyncResetSynchronizer(self.cd_eth_rx, reset), ]