def __init__(self, wishbone, lasmim): ### # Control FSM self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(wishbone.cyc & wishbone.stb, NextState("REQUEST"))) fsm.act( "REQUEST", lasmim.stb.eq(1), lasmim.we.eq(wishbone.we), If( lasmim.req_ack, If(wishbone.we, NextState("WRITE_DATA")).Else(NextState("READ_DATA")))) fsm.act( "WRITE_DATA", If(lasmim.dat_w_ack, lasmim.dat_we.eq(wishbone.sel), wishbone.ack.eq(1), NextState("IDLE"))) fsm.act("READ_DATA", If(lasmim.dat_r_ack, wishbone.ack.eq(1), NextState("IDLE"))) # Address / Datapath self.comb += [ lasmim.adr.eq(wishbone.adr), If( lasmim.dat_w_ack, lasmim.dat_w.eq(wishbone.dat_w), ), wishbone.dat_r.eq(lasmim.dat_r) ]
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) 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, clock_pads, pads, with_hw_init_reset): 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 = Signal() if with_hw_init_reset: self.submodules.hw_reset = LiteEthPHYHWReset() self.comb += reset.eq(self._reset.storage | self.hw_reset.reset) else: self.comb += reset.eq(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, phy_settings, geom_settings, timing_settings): if phy_settings.memtype in ["SDR"]: burst_length = phy_settings.nphases * 1 # command multiplication*SDR elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]: burst_length = phy_settings.nphases * 2 # command multiplication*DDR burst_width = phy_settings.dfi_databits * phy_settings.nphases address_align = log2_int(burst_length) # # # self.dfi = dfi = dfibus.Interface(geom_settings.addressbits, geom_settings.bankbits, phy_settings.dfi_databits, phy_settings.nphases) self.bus = bus = wishbone.Interface(burst_width) rdphase = phy_settings.rdphase wrphase = phy_settings.wrphase precharge_all = Signal() activate = Signal() refresh = Signal() write = Signal() read = Signal() # Compute current column, bank and row from wishbone address slicer = _AddressSlicer(geom_settings.colbits, geom_settings.bankbits, geom_settings.rowbits, address_align) # Manage banks bank_idle = Signal() bank_hit = Signal() banks = [] for i in range(2**geom_settings.bankbits): bank = _Bank(geom_settings) self.comb += [ bank.open.eq(activate), bank.reset.eq(precharge_all), bank.row.eq(slicer.row(bus.adr)) ] banks.append(bank) self.submodules += banks cases = {} for i, bank in enumerate(banks): cases[i] = [bank.ce.eq(1)] self.comb += Case(slicer.bank(bus.adr), cases) self.comb += [ bank_hit.eq(reduce(or_, [bank.hit & bank.ce for bank in banks])), bank_idle.eq(reduce(or_, [bank.idle & bank.ce for bank in banks])), ] # Timings write2precharge_timer = WaitTimer(2 + timing_settings.tWR - 1) self.submodules += write2precharge_timer self.comb += write2precharge_timer.wait.eq(~write) refresh_timer = WaitTimer(timing_settings.tREFI) self.submodules += refresh_timer self.comb += refresh_timer.wait.eq(~refresh) # Main FSM self.submodules.fsm = fsm = FSM() fsm.act( "IDLE", If(refresh_timer.done, NextState("PRECHARGE-ALL")).Elif( bus.stb & bus.cyc, If(bank_hit, If(bus.we, NextState("WRITE")).Else(NextState("READ"))).Elif( ~bank_idle, If(write2precharge_timer.done, NextState("PRECHARGE"))).Else( NextState("ACTIVATE")))) fsm.act( "READ", read.eq(1), dfi.phases[rdphase].ras_n.eq(1), dfi.phases[rdphase].cas_n.eq(0), dfi.phases[rdphase].we_n.eq(1), dfi.phases[rdphase].rddata_en.eq(1), NextState("WAIT-READ-DONE"), ) fsm.act( "WAIT-READ-DONE", If(dfi.phases[rdphase].rddata_valid, bus.ack.eq(1), NextState("IDLE"))) fsm.act("WRITE", write.eq(1), dfi.phases[wrphase].ras_n.eq(1), dfi.phases[wrphase].cas_n.eq(0), dfi.phases[wrphase].we_n.eq(0), dfi.phases[wrphase].wrdata_en.eq(1), NextState("WRITE-LATENCY")) fsm.act("WRITE-ACK", bus.ack.eq(1), NextState("IDLE")) fsm.act("PRECHARGE-ALL", precharge_all.eq(1), dfi.phases[rdphase].ras_n.eq(0), dfi.phases[rdphase].cas_n.eq(1), dfi.phases[rdphase].we_n.eq(0), NextState("PRE-REFRESH")) fsm.act( "PRECHARGE", # do no reset bank since we are going to re-open it dfi.phases[0].ras_n.eq(0), dfi.phases[0].cas_n.eq(1), dfi.phases[0].we_n.eq(0), NextState("TRP")) fsm.act( "ACTIVATE", activate.eq(1), dfi.phases[0].ras_n.eq(0), dfi.phases[0].cas_n.eq(1), dfi.phases[0].we_n.eq(1), NextState("TRCD"), ) fsm.act("REFRESH", refresh.eq(1), dfi.phases[rdphase].ras_n.eq(0), dfi.phases[rdphase].cas_n.eq(0), dfi.phases[rdphase].we_n.eq(1), NextState("POST-REFRESH")) fsm.delayed_enter("WRITE-LATENCY", "WRITE-ACK", phy_settings.write_latency - 1) fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP - 1) fsm.delayed_enter("TRCD", "IDLE", timing_settings.tRCD - 1) fsm.delayed_enter("PRE-REFRESH", "REFRESH", timing_settings.tRP - 1) fsm.delayed_enter("POST-REFRESH", "IDLE", timing_settings.tRFC - 1) # DFI commands for phase in dfi.phases: if hasattr(phase, "reset_n"): self.comb += phase.reset_n.eq(1) if hasattr(phase, "odt"): self.comb += phase.odt.eq(1) self.comb += [ phase.cke.eq(1), phase.cs_n.eq(0), phase.bank.eq(slicer.bank(bus.adr)), If(precharge_all, phase.address.eq(2**10)).Elif( activate, phase.address.eq(slicer.row(bus.adr))).Elif( write | read, phase.address.eq(slicer.col(bus.adr))) ] # DFI datapath self.comb += [ bus.dat_r.eq(Cat(phase.rddata for phase in dfi.phases)), Cat(phase.wrdata for phase in dfi.phases).eq(bus.dat_w), Cat(phase.wrdata_mask for phase in dfi.phases).eq(~bus.sel), ]
def __init__(self, geom_settings, timing_settings, controller_settings, address_align, bankn, req): self.refresh_req = Signal() self.refresh_gnt = Signal() self.cmd = CommandRequestRW(geom_settings.addressbits, geom_settings.bankbits) ### # Request FIFO layout = [("we", 1), ("adr", len(req.adr))] req_in = Record(layout) reqf = Record(layout) self.submodules.req_fifo = SyncFIFO(layout_len(layout), controller_settings.req_queue_size) self.comb += [ self.req_fifo.din.eq(req_in.raw_bits()), reqf.raw_bits().eq(self.req_fifo.dout) ] self.comb += [ req_in.we.eq(req.we), req_in.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_w_ack | req.dat_r_ack), req.lock.eq(self.req_fifo.readable) ] slicer = _AddressSlicer(geom_settings.colbits, address_align) # Row tracking has_openrow = Signal() openrow = Signal(geom_settings.rowbits) 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_w_ack.eq(self.cmd.ack & reqf.we), req.dat_r_ack.eq(self.cmd.ack & ~reqf.we), 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, phy_settings, geom_settings, timing_settings, controller_settings, bank_machines, refresher, dfi, lasmic, with_bandwidth=False): assert (phy_settings.nphases == len(dfi.phases)) self.phy_settings = phy_settings # Command choosing requests = [bm.cmd for bm in bank_machines] self.submodules.choose_cmd = choose_cmd = _CommandChooser(requests) self.submodules.choose_req = 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) ] # Command steering nop = CommandRequest(geom_settings.addressbits, geom_settings.bankbits) 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( reduce(or_, [req.stb & req.is_read for req in requests])), write_available.eq( reduce(or_, [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( controller_settings.read_time) write_time_en, max_write_time = anti_starvation( controller_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( reduce(and_, [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), refresher.ack.eq(1), 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) if controller_settings.with_bandwidth: data_width = phy_settings.dfi_databits * phy_settings.nphases self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
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(sink.data) header_words = (header.length * 8) // dw 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) ) 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.ready.eq(1), counter_reset.eq(1), If(sink.valid, shift.eq(1), NextState(idle_next_state))) if header_words != 1: fsm.act( "RECEIVE_HEADER", sink.ready.eq(1), If(sink.valid, counter_ce.eq(1), shift.eq(1), If(counter == header_words - 2, NextState("COPY")))) no_payload = Signal() self.sync += \ If(fsm.before_entering("COPY"), no_payload.eq(sink.last) ) if hasattr(sink, "error"): self.comb += source.error.eq(sink.error) self.comb += [ source.last.eq(sink.last | no_payload), source.data.eq(sink.data), header.decode(self.header, source) ] fsm.act( "COPY", sink.ready.eq(source.ready), source.valid.eq(sink.valid | no_payload), If(source.valid & source.ready & source.last, NextState("IDLE")))
def __init__(self, cachesize, master, slave): self.master = master self.slave = slave ### dw_from = len(master.dat_r) dw_to = len(slave.dat_r) if dw_to > dw_from and (dw_to % dw_from) != 0: raise ValueError( "Slave data width must be a multiple of {dw}".format( dw=dw_from)) if dw_to < dw_from and (dw_from % dw_to) != 0: raise ValueError( "Master data width must be a multiple of {dw}".format( dw=dw_to)) # Split address: # TAG | LINE NUMBER | LINE OFFSET offsetbits = log2_int(max(dw_to // dw_from, 1)) addressbits = len(slave.adr) + offsetbits linebits = log2_int(cachesize) - offsetbits tagbits = addressbits - linebits wordbits = log2_int(max(dw_from // dw_to, 1)) adr_offset, adr_line, adr_tag = split(master.adr, offsetbits, linebits, tagbits) word = Signal(wordbits) if wordbits else None # Data memory data_mem = Memory(dw_to * 2**wordbits, 2**linebits) data_port = data_mem.get_port(write_capable=True, we_granularity=8) self.specials += data_mem, data_port write_from_slave = 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_slave, displacer(slave.dat_r, word, data_port.dat_w), displacer(Replicate(1, dw_to // 8), word, data_port.we)).Else( data_port.dat_w.eq( Replicate(master.dat_w, max(dw_to // dw_from, 1))), If( master.cyc & master.stb & master.we & master.ack, displacer(master.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True))), chooser(data_port.dat_r, word, slave.dat_w), slave.sel.eq(2**(dw_to // 8) - 1), chooser(data_port.dat_r, adr_offset_r, master.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 += slave.adr.eq(Cat(word, adr_line, tag_do.tag)) else: self.comb += slave.adr.eq(Cat(adr_line, tag_do.tag)) # slave 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 self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(master.cyc & master.stb, NextState("TEST_HIT"))) fsm.act( "TEST_HIT", word_clr.eq(1), If(tag_do.tag == adr_tag, master.ack.eq(1), If(master.we, tag_di.dirty.eq(1), tag_port.we.eq(1)), NextState("IDLE")).Else( If(tag_do.dirty, NextState("EVICT")).Else(NextState("REFILL_WRTAG")))) fsm.act( "EVICT", slave.stb.eq(1), slave.cyc.eq(1), slave.we.eq(1), If(slave.ack, word_inc.eq(1), If(word_is_last(word), NextState("REFILL_WRTAG")))) fsm.act( "REFILL_WRTAG", # Write the tag first to set the slave address tag_port.we.eq(1), word_clr.eq(1), NextState("REFILL")) fsm.act( "REFILL", slave.stb.eq(1), slave.cyc.eq(1), slave.we.eq(0), If( slave.ack, write_from_slave.eq(1), word_inc.eq(1), If( word_is_last(word), NextState("TEST_HIT"), ).Else(NextState("REFILL"))))
def __init__(self, master, slave): dw_from = len(master.dat_r) dw_to = len(slave.dat_w) ratio = dw_to // dw_from ratiobits = log2_int(ratio) # # # write = Signal() evict = Signal() refill = Signal() read = Signal() address = FlipFlop(30) self.submodules += address self.comb += address.d.eq(master.adr) counter = Signal(max=ratio) counter_ce = Signal() counter_reset = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) counter_offset = Signal(max=ratio) counter_done = Signal() self.comb += [ counter_offset.eq(address.q), counter_done.eq((counter + counter_offset) == ratio - 1) ] cached_data = Signal(dw_to) cached_sel = Signal(dw_to // 8) end_of_burst = Signal() self.comb += end_of_burst.eq(~master.cyc | (master.stb & master.cyc & master.ack & ((master.cti == 7) | counter_done))) need_refill = FlipFlop(reset=1) self.submodules += need_refill self.comb += [need_refill.reset.eq(end_of_burst), need_refill.d.eq(0)] # Main FSM self.submodules.fsm = fsm = FSM() fsm.act( "IDLE", counter_reset.eq(1), If( master.stb & master.cyc, address.ce.eq(1), If(master.we, NextState("WRITE")).Else( If(need_refill.q, NextState("REFILL")).Else(NextState("READ"))))) fsm.act( "WRITE", If(master.stb & master.cyc, write.eq(1), counter_ce.eq(1), master.ack.eq(1), If(counter_done, NextState("EVICT"))).Elif(~master.cyc, NextState("EVICT"))) fsm.act("EVICT", evict.eq(1), slave.stb.eq(1), slave.we.eq(1), slave.cyc.eq(1), slave.dat_w.eq(cached_data), slave.sel.eq(cached_sel), If(slave.ack, NextState("IDLE"))) fsm.act("REFILL", refill.eq(1), slave.stb.eq(1), slave.cyc.eq(1), If(slave.ack, need_refill.ce.eq(1), NextState("READ"))) fsm.act("READ", read.eq(1), If(master.stb & master.cyc, master.ack.eq(1)), NextState("IDLE")) # Address self.comb += [ slave.cti.eq( 7), # we are not able to generate bursts since up-converting slave.adr.eq(address.q[ratiobits:]) ] # Datapath cached_datas = [FlipFlop(dw_from) for i in range(ratio)] cached_sels = [FlipFlop(dw_from // 8) for i in range(ratio)] self.submodules += cached_datas, cached_sels cases = {} for i in range(ratio): write_sel = Signal() cases[i] = write_sel.eq(1) self.comb += [ cached_sels[i].reset.eq(counter_reset), If( write, cached_datas[i].d.eq(master.dat_w), ).Else(cached_datas[i].d.eq(slave.dat_r[dw_from * i:dw_from * (i + 1)])), cached_sels[i].d.eq(master.sel), If((write & write_sel) | refill, cached_datas[i].ce.eq(1), cached_sels[i].ce.eq(1)) ] self.comb += Case(counter + counter_offset, cases) cases = {} for i in range(ratio): cases[i] = master.dat_r.eq(cached_datas[i].q) self.comb += Case(address.q[:ratiobits], cases) self.comb += [ cached_data.eq(Cat([cached_data.q for cached_data in cached_datas])), cached_sel.eq(Cat([cached_sel.q for cached_sel in cached_sels])) ]
def __init__(self, master, slave): dw_from = len(master.dat_r) dw_to = len(slave.dat_w) ratio = dw_from // dw_to # # # read = Signal() write = Signal() counter = Signal(max=ratio) counter_reset = Signal() counter_ce = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) counter_done = Signal() self.comb += counter_done.eq(counter == ratio - 1) # Main FSM self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", counter_reset.eq(1), If(master.stb & master.cyc, If(master.we, NextState("WRITE")).Else(NextState("READ")))) fsm.act( "WRITE", write.eq(1), slave.we.eq(1), slave.cyc.eq(1), If( master.stb & master.cyc, slave.stb.eq(1), If(slave.ack, counter_ce.eq(1), If(counter_done, master.ack.eq(1), NextState("IDLE")))).Elif(~master.cyc, NextState("IDLE"))) fsm.act( "READ", read.eq(1), slave.cyc.eq(1), If( master.stb & master.cyc, slave.stb.eq(1), If(slave.ack, counter_ce.eq(1), If(counter_done, master.ack.eq(1), NextState("IDLE")))).Elif(~master.cyc, NextState("IDLE"))) # Address self.comb += [ If( counter_done, slave.cti.eq(7) # indicate end of burst ).Else(slave.cti.eq(2)), slave.adr.eq(Cat(counter, master.adr)) ] # Datapath cases = {} for i in range(ratio): cases[i] = [ slave.sel.eq(master.sel[i * dw_to // 8:(i + 1) * dw_to]), slave.dat_w.eq(master.dat_w[i * dw_to:(i + 1) * dw_to]) ] self.comb += Case(counter, cases) cached_data = Signal(dw_from) self.comb += master.dat_r.eq(Cat(cached_data[dw_to:], slave.dat_r)) self.sync += \ If(read & counter_ce, cached_data.eq(master.dat_r) )
def __init__(self, pads, default=_default_edid): self._hpd_notif = CSRStatus() self._hpd_en = CSRStorage() mem_size = len(default) assert mem_size%128 == 0 self.specials.mem = Memory(8, mem_size, init=default) # # # # HPD if hasattr(pads, "hpd_notif"): self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status) else: self.comb += self._hpd_notif.status.eq(1) if hasattr(pads, "hpd_en"): self.comb += pads.hpd_en.eq(self._hpd_en.storage) # EDID scl_raw = Signal() sda_i = Signal() sda_raw = Signal() sda_drv = Signal() _sda_drv_reg = Signal() _sda_i_async = Signal() self.sync += _sda_drv_reg.eq(sda_drv) pad_scl = getattr(pads, "scl") if hasattr(pad_scl, "inverted"): self.specials += MultiReg(pads.scl, scl_raw) else: self.specials += MultiReg(~pads.scl, scl_raw) self.specials += [ Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async), MultiReg(_sda_i_async, sda_raw) ] # for debug self.scl = scl_raw self.sda_i = sda_i self.sda_o = Signal() self.comb += self.sda_o.eq(~_sda_drv_reg) self.sda_oe = _sda_drv_reg 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), sda_i.eq(sda_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])) ) ) ] self.din = din self.counter = counter is_read = Signal() update_is_read = Signal() self.sync += If(update_is_read, is_read.eq(din[0])) offset_counter = Signal(max=mem_size) 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.specials += rdport 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) ) self.submodules.fsm = fsm = FSM() fsm.act("WAIT_START") fsm.act("RCV_ADDRESS", If(counter == 8, If(din[1:] == 0x50, update_is_read.eq(1), NextState("ACK_ADDRESS0") ).Else( NextState("WAIT_START") ) ) ) fsm.act("ACK_ADDRESS0", If(~scl_i, NextState("ACK_ADDRESS1")) ) fsm.act("ACK_ADDRESS1", zero_drv.eq(1), If(scl_i, NextState("ACK_ADDRESS2")) ) fsm.act("ACK_ADDRESS2", zero_drv.eq(1), If(~scl_i, If(is_read, NextState("READ") ).Else( NextState("RCV_OFFSET") ) ) ) fsm.act("RCV_OFFSET", If(counter == 8, oc_load.eq(1), NextState("ACK_OFFSET0") ) ) fsm.act("ACK_OFFSET0", If(~scl_i, NextState("ACK_OFFSET1") ) ) fsm.act("ACK_OFFSET1", zero_drv.eq(1), If(scl_i, NextState("ACK_OFFSET2") ) ) fsm.act("ACK_OFFSET2", zero_drv.eq(1), If(~scl_i, NextState("RCV_ADDRESS") ) ) fsm.act("READ", If(~scl_i, If(counter == 8, data_drv_stop.eq(1), NextState("ACK_READ") ).Else( data_drv_en.eq(1) ) ) ) fsm.act("ACK_READ", If(scl_rising, oc_inc.eq(1), If(sda_i, NextState("WAIT_START") ).Else( NextState("READ") ) ) ) for state in fsm.actions.keys(): fsm.act(state, If(start, NextState("RCV_ADDRESS"))) if hasattr(pads, "hpd_en"): fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
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, 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) ).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, phy, clk_freq): self.wishbone = wishbone.Interface() # # # byte_counter = Signal(3) byte_counter_reset = Signal() byte_counter_ce = Signal() self.sync += \ If(byte_counter_reset, byte_counter.eq(0) ).Elif(byte_counter_ce, byte_counter.eq(byte_counter + 1) ) word_counter = Signal(3) word_counter_reset = Signal() word_counter_ce = Signal() self.sync += \ If(word_counter_reset, word_counter.eq(0) ).Elif(word_counter_ce, word_counter.eq(word_counter + 1) ) cmd = Signal(8) cmd_ce = Signal() length = Signal(8) length_ce = Signal() address = Signal(32) address_ce = Signal() data = Signal(32) rx_data_ce = Signal() tx_data_ce = Signal() self.sync += [ If(cmd_ce, cmd.eq(phy.source.data)), If(length_ce, length.eq(phy.source.data)), If(address_ce, address.eq(Cat(phy.source.data, address[0:24]))), If(rx_data_ce, data.eq(Cat(phy.source.data, data[0:24]))).Elif(tx_data_ce, data.eq(self.wishbone.dat_r)) ] fsm = ResetInserter()(FSM(reset_state="IDLE")) timer = WaitTimer(clk_freq // 10) self.submodules += fsm, timer self.comb += [fsm.reset.eq(timer.done), phy.source.ready.eq(1)] fsm.act( "IDLE", If( phy.source.valid, cmd_ce.eq(1), If((phy.source.data == self.cmds["write"]) | (phy.source.data == self.cmds["read"]), NextState("RECEIVE_LENGTH")), byte_counter_reset.eq(1), word_counter_reset.eq(1))) fsm.act( "RECEIVE_LENGTH", If(phy.source.valid, length_ce.eq(1), NextState("RECEIVE_ADDRESS"))) fsm.act( "RECEIVE_ADDRESS", If( phy.source.valid, address_ce.eq(1), byte_counter_ce.eq(1), If( byte_counter == 3, If(cmd == self.cmds["write"], NextState("RECEIVE_DATA")).Elif( cmd == self.cmds["read"], NextState("READ_DATA")), byte_counter_reset.eq(1), ))) fsm.act( "RECEIVE_DATA", If( phy.source.valid, rx_data_ce.eq(1), byte_counter_ce.eq(1), If(byte_counter == 3, NextState("WRITE_DATA"), byte_counter_reset.eq(1)))) self.comb += [ self.wishbone.adr.eq(address + word_counter), self.wishbone.dat_w.eq(data), self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1) ] fsm.act( "WRITE_DATA", self.wishbone.stb.eq(1), self.wishbone.we.eq(1), self.wishbone.cyc.eq(1), If( self.wishbone.ack, word_counter_ce.eq(1), If(word_counter == (length - 1), NextState("IDLE")).Else(NextState("RECEIVE_DATA")))) fsm.act( "READ_DATA", self.wishbone.stb.eq(1), self.wishbone.we.eq(0), self.wishbone.cyc.eq(1), If(self.wishbone.ack, tx_data_ce.eq(1), NextState("SEND_DATA"))) self.comb += \ chooser(data, byte_counter, phy.sink.data, n=4, reverse=True) fsm.act( "SEND_DATA", phy.sink.valid.eq(1), If( phy.sink.ready, byte_counter_ce.eq(1), If( byte_counter == 3, word_counter_ce.eq(1), If(word_counter == (length - 1), NextState("IDLE")).Else(NextState("READ_DATA"), byte_counter_reset.eq(1))))) self.comb += timer.wait.eq(~fsm.ongoing("IDLE")) self.comb += phy.sink.last.eq((byte_counter == 3) & (word_counter == length - 1)) if hasattr(phy.sink, "length"): self.comb += phy.sink.length.eq(4 * length)
def __init__(self, pads, rd_timing, wr_timing): self.bus = wishbone.Interface() ### data = TSTriple(16) lsb = Signal() self.specials += data.get_tristate(pads.d) self.comb += [data.oe.eq(pads.oe_n), pads.ce_n.eq(0)] load_lo = Signal() load_hi = Signal() store = Signal() pads.oe_n.reset, pads.we_n.reset = 1, 1 self.sync += [ pads.oe_n.eq(1), pads.we_n.eq(1), # Register data/address to avoid off-chip glitches If( self.bus.cyc & self.bus.stb, pads.adr.eq(Cat(lsb, self.bus.adr)), If( self.bus.we, # Only 16-bit writes are supported. Assume sel=0011 or 1100. If(self.bus.sel[0], data.o.eq(self.bus.dat_w[:16])).Else( data.o.eq(self.bus.dat_w[16:]) )).Else(pads.oe_n.eq(0))), If(load_lo, self.bus.dat_r[:16].eq(data.i)), If(load_hi, self.bus.dat_r[16:].eq(data.i)), If(store, pads.we_n.eq(0)) ] # Typical timing of the flash chips: # - 110ns address to output # - 50ns write pulse width counter = Signal(max=max(rd_timing, wr_timing) + 1) counter_en = Signal() counter_wr_mode = Signal() counter_done = Signal() self.comb += counter_done.eq( counter == Mux(counter_wr_mode, wr_timing, rd_timing)) self.sync += If(counter_en & ~counter_done, counter.eq(counter + 1)).Else(counter.eq(0)) fsm = FSM() self.submodules += fsm fsm.act( "IDLE", If(self.bus.cyc & self.bus.stb, If(self.bus.we, NextState("WR")).Else(NextState("RD_HI")))) fsm.act("RD_HI", lsb.eq(0), counter_en.eq(1), If(counter_done, load_hi.eq(1), NextState("RD_LO"))) fsm.act("RD_LO", lsb.eq(1), counter_en.eq(1), If(counter_done, load_lo.eq(1), NextState("ACK"))) fsm.act( "WR", # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0] lsb.eq(self.bus.sel[0]), counter_wr_mode.eq(1), counter_en.eq(1), store.eq(1), If(counter_done, NextState("ACK"))) fsm.act("ACK", self.bus.ack.eq(1), NextState("IDLE"))
def __init__(self, pads): STATUS_FULL = 1 STATUS_EMPTY = 2 self.shift_reg = shift_reg = CSRStorage(8, write_from_dev=True) self.status = status = CSRStorage(2, reset=STATUS_EMPTY, write_from_dev=True) self.slave_addr = slave_addr = CSRStorage(7) ### scl_raw = Signal() sda_i = Signal() sda_raw = Signal() sda_drv = Signal() scl_drv = Signal() _sda_drv_reg = Signal() self._sda_i_async = _sda_i_async = Signal() self._scl_i_async = _scl_i_async = Signal() _scl_drv_reg = Signal() self.sync += _sda_drv_reg.eq(sda_drv) self.sync += _scl_drv_reg.eq(scl_drv) self.comb += [ pads.scl.w.eq(0), pads.scl.oe.eq(_scl_drv_reg), _scl_i_async.eq(pads.scl.r), pads.sda.w.eq(0), pads.sda.oe.eq(_sda_drv_reg), _sda_i_async.eq(pads.sda.r), ] self.specials += [ MultiReg(_scl_i_async, scl_raw), MultiReg(_sda_i_async, sda_raw), ] # for debug self.scl = scl_raw self.sda_i = sda_i self.sda_o = Signal() self.comb += self.sda_o.eq(~_sda_drv_reg) self.sda_oe = _sda_drv_reg shift_reg_full = Signal() shift_reg_empty = Signal() scl_i = Signal() samp_count = Signal(3) samp_carry = Signal() self.sync += [ Cat(samp_count, samp_carry).eq(samp_count + 1), If(samp_carry, scl_i.eq(scl_raw), sda_i.eq(sda_raw)) ] scl_r = Signal() sda_r = Signal() scl_rising = Signal() scl_falling = Signal() sda_rising = Signal() sda_falling = Signal() self.sync += [scl_r.eq(scl_i), sda_r.eq(sda_i)] self.comb += [ shift_reg_full.eq(status.storage[0]), shift_reg_empty.eq(status.storage[1]), scl_rising.eq(scl_i & ~scl_r), scl_falling.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) counter_reset = Signal() self.sync += [ If(start | counter_reset, counter.eq(0)), If( scl_rising, If(counter == 8, counter.eq(0)).Else(counter.eq(counter + 1), din.eq(Cat(sda_i, din[:7])))) ] self.din = din self.counter = counter is_read = Signal() update_is_read = Signal() self.sync += If(update_is_read, is_read.eq(din[0])) data_bit = Signal() zero_drv = Signal() data_drv = Signal() pause_drv = Signal() self.comb += scl_drv.eq(pause_drv) 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(shift_reg.storage, counter, data_bit, 8, reverse=True)) self.submodules.fsm = fsm = FSM() fsm.act( "WAIT_START", data_drv_stop.eq(1), ) fsm.act( "RCV_ADDRESS", data_drv_stop.eq(1), If( counter == 8, If( din[1:] == slave_addr.storage, update_is_read.eq(1), NextState("ACK_ADDRESS0"), ).Else(NextState("WAIT_START"), ))) fsm.act( "ACK_ADDRESS0", counter_reset.eq(1), If(~scl_i, NextState("ACK_ADDRESS1")), ) fsm.act( "ACK_ADDRESS1", counter_reset.eq(1), zero_drv.eq(1), If(scl_i, NextState("ACK_ADDRESS2")), ) fsm.act("ACK_ADDRESS2", counter_reset.eq(1), zero_drv.eq(1), If(~scl_i, NextState("PAUSE"))) fsm.act( "PAUSE", counter_reset.eq(1), pause_drv.eq(1), If( ~shift_reg_empty & is_read, counter_reset.eq(1), NextState("DO_READ"), ).Elif( ~shift_reg_full & ~is_read, NextState("DO_WRITE"), )) fsm.act( "DO_READ", If( ~scl_i, If( counter == 8, data_drv_stop.eq(1), status.we.eq(1), status.dat_w.eq(STATUS_EMPTY), NextState("ACK_READ0"), ).Else(data_drv_en.eq(1), ))) fsm.act( "ACK_READ0", counter_reset.eq(1), If( scl_rising, If( sda_i, NextState("WAIT_START"), ).Else(NextState("ACK_READ1"), ))) fsm.act("ACK_READ1", counter_reset.eq(1), If( scl_falling, NextState("PAUSE"), )) fsm.act( "DO_WRITE", If( counter == 8, shift_reg.dat_w.eq(din), shift_reg.we.eq(1), NextState("ACK_WRITE0"), )) fsm.act( "ACK_WRITE0", counter_reset.eq(1), If(~scl_i, NextState("ACK_WRITE1")), ) fsm.act( "ACK_WRITE1", counter_reset.eq(1), zero_drv.eq(1), If(scl_i, NextState("ACK_WRITE2")), ) fsm.act( "ACK_WRITE2", counter_reset.eq(1), zero_drv.eq(1), If( ~scl_i, NextState("PAUSE"), status.we.eq(1), status.dat_w.eq(STATUS_FULL), )) for state in fsm.actions.keys(): fsm.act(state, If(start, NextState("RCV_ADDRESS"))) for state in fsm.actions.keys(): fsm.act(state, If(self.slave_addr.re, NextState("WAIT_START")))