def __init__(self, nbits=11): self.valid_i = Signal() self.vsync = Signal() self.de = Signal() self._hres = CSRStatus(nbits) self._vres = CSRStatus(nbits) # # # # Detect DE transitions de_r = Signal() pn_de = Signal() self.sync.pix += de_r.eq(self.de) self.comb += pn_de.eq(~self.de & de_r) # HRES hcounter = Signal(nbits) self.sync.pix += \ If(self.valid_i & self.de, hcounter.eq(hcounter + 1) ).Else( hcounter.eq(0) ) hcounter_st = Signal(nbits) self.sync.pix += \ If(self.valid_i, If(pn_de, hcounter_st.eq(hcounter)) ).Else( hcounter_st.eq(0) ) self.specials += MultiReg(hcounter_st, self._hres.status) # VRES vsync_r = Signal() p_vsync = Signal() self.sync.pix += vsync_r.eq(self.vsync), self.comb += p_vsync.eq(self.vsync & ~vsync_r) vcounter = Signal(nbits) self.sync.pix += \ If(self.valid_i & p_vsync, vcounter.eq(0) ).Elif(pn_de, vcounter.eq(vcounter + 1) ) vcounter_st = Signal(nbits) self.sync.pix += \ If(self.valid_i, If(p_vsync, vcounter_st.eq(vcounter)) ).Else( vcounter_st.eq(0) ) self.specials += MultiReg(vcounter_st, self._vres.status)
def __init__(self, width, depth): _FIFOInterface.__init__(self, width, depth) ### depth_bits = log2_int(depth, True) produce = ClockDomainsRenamer("write")(GrayCounter(depth_bits + 1)) consume = ClockDomainsRenamer("read")(GrayCounter(depth_bits + 1)) self.submodules += produce, consume self.comb += [ produce.ce.eq(self.writable & self.we), consume.ce.eq(self.readable & self.re) ] produce_rdomain = Signal(depth_bits + 1) self.specials += [ NoRetiming(produce.q), MultiReg(produce.q, produce_rdomain, "read") ] consume_wdomain = Signal(depth_bits + 1) self.specials += [ NoRetiming(consume.q), MultiReg(consume.q, consume_wdomain, "write") ] if depth_bits == 1: self.comb += self.writable.eq( (produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2])) else: self.comb += [ self.writable.eq((produce.q[-1] == consume_wdomain[-1]) | (produce.q[-2] == consume_wdomain[-2]) | (produce.q[:-2] != consume_wdomain[:-2])) ] self.comb += self.readable.eq(consume.q != produce_rdomain) storage = Memory(self.width, depth) self.specials += storage wrport = storage.get_port(write_capable=True, clock_domain="write") self.specials += wrport self.comb += [ wrport.adr.eq(produce.q_binary[:-1]), wrport.dat_w.eq(self.din), wrport.we.eq(produce.ce) ] rdport = storage.get_port(clock_domain="read") self.specials += rdport self.comb += [ rdport.adr.eq(consume.q_next_binary[:-1]), self.dout.eq(rdport.dat_r) ]
def __init__(self, period, width=6): self.clk = Signal() self.value = CSRStatus(32) # # # self.clock_domains.cd_fmeter = ClockDomain(reset_less=True) self.comb += self.cd_fmeter.clk.eq(self.clk) # period generation period_done = Signal() period_counter = Signal(32) self.comb += period_done.eq(period_counter == period) self.sync += \ If(period_done, period_counter.eq(0), ).Else( period_counter.eq(period_counter + 1) ) # frequency measurement event_counter = ClockDomainsRenamer("fmeter")(GrayCounter(width)) gray_decoder = GrayDecoder(width) sampler = Sampler(width) self.submodules += event_counter, gray_decoder, sampler self.specials += MultiReg(event_counter.q, gray_decoder.i) self.comb += [ event_counter.ce.eq(1), sampler.latch.eq(period_done), sampler.i.eq(gray_decoder.o), self.value.status.eq(sampler.o) ]
def __init__(self, measure_clock, measure_period, measure_width=6, counter_width=32): self.value = CSRStatus(counter_width) # # # # create measure clock domain self.clock_domains.cd_measure = ClockDomain(reset_less=True) self.comb += self.cd_measure.clk.eq(measure_clock) # mesure period period_done = Signal() period_counter = Signal(counter_width) self.comb += period_done.eq(period_counter == measure_period) self.sync += \ If(period_done, period_counter.eq(0), ).Else( period_counter.eq(period_counter + 1) ) # measurement event_counter = ClockDomainsRenamer("measure")(GrayCounter(measure_width)) gray_decoder = GrayDecoder(measure_width) sampler = Sampler(measure_width, counter_width) self.submodules += event_counter, gray_decoder, sampler self.specials += MultiReg(event_counter.q, gray_decoder.i) self.comb += [ event_counter.ce.eq(1), sampler.latch.eq(period_done), sampler.i.eq(gray_decoder.o), self.value.status.eq(sampler.value) ]
def __init__(self, dw, cd): self.sink = stream.Endpoint(core_layout(dw)) self.source = stream.Endpoint(core_layout(dw)) self.value = CSRStorage(16) # # # sync_cd = getattr(self.sync, cd) value = Signal(16) self.specials += MultiReg(self.value.storage, value, cd) counter = Signal(16) done = Signal() sync_cd += \ If(self.source.ready, If(done, counter.eq(0) ).Elif(self.sink.valid, counter.eq(counter + 1) ) ) self.comb += [ done.eq(counter == value), self.sink.connect(self.source, omit=set(["valid"])), self.source.valid.eq(self.sink.valid & done) ]
def __init__(self, required_controls=8): self.raw_data = Signal(10) self.synced = Signal() self.data = Signal(10) self._char_synced = CSRStatus() self._ctl_pos = CSRStatus(bits_for(9)) # # # raw_data1 = Signal(10) self.sync.pix += raw_data1.eq(self.raw_data) raw = Signal(20) self.comb += raw.eq(Cat(raw_data1, self.raw_data)) found_control = Signal() control_position = Signal(max=10) self.sync.pix += found_control.eq(0) for i in range(10): self.sync.pix += If( reduce(or_, [raw[i:i + 10] == t for t in control_tokens]), found_control.eq(1), control_position.eq(i)) control_counter = Signal(max=required_controls) previous_control_position = Signal(max=10) word_sel = Signal(max=10) self.sync.pix += [ If( found_control & (control_position == previous_control_position), If(control_counter == (required_controls - 1), control_counter.eq(0), self.synced.eq(1), word_sel.eq(control_position)).Else( control_counter.eq(control_counter + 1))).Else( control_counter.eq(0)), previous_control_position.eq(control_position) ] self.specials += [ MultiReg(self.synced, self._char_synced.status), MultiReg(word_sel, self._ctl_pos.status) ] self.sync.pix += self.data.eq(raw >> word_sel)
def __init__(self, dw, cd): self.sink = stream.Endpoint(core_layout(dw)) self.source = stream.Endpoint(core_layout(dw)) self.value = CSRStorage(dw) self.mask = CSRStorage(dw) # # # value = Signal(dw) mask = Signal(dw) self.specials += [ MultiReg(self.value.storage, value, cd), MultiReg(self.mask.storage, mask, cd) ] self.comb += [ self.sink.connect(self.source), self.source.hit.eq((self.sink.data & mask) == value) ]
def __init__(self, pads): self.source = source = stream.Endpoint(eth_phy_description(8)) # # # converter = stream.StrideConverter(converter_description(2), converter_description(8)) converter = ResetInserter()(converter) self.submodules += converter converter_sink_valid = Signal() converter_sink_data = Signal(2) self.specials += [ MultiReg(converter_sink_valid, converter.sink.valid, n=2), MultiReg(converter_sink_data, converter.sink.data, n=2) ] crs_dv = Signal() crs_dv_d = Signal() rx_data = Signal(2) self.sync += [ crs_dv.eq(pads.crs_dv), crs_dv_d.eq(crs_dv), rx_data.eq(pads.rx_data) ] self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", If(crs_dv & (rx_data != 0b00), converter_sink_valid.eq(1), converter_sink_data.eq(rx_data), NextState("RECEIVE")).Else(converter.reset.eq(1))) fsm.act( "RECEIVE", converter_sink_valid.eq(1), converter_sink_data.eq(rx_data), # end of frame when 2 consecutives 0 on crs_dv If(~(crs_dv | crs_dv_d), converter.sink.last.eq(1), NextState("IDLE"))) self.comb += converter.source.connect(source)
def __init__(self, core): self.enable = CSRStorage() self.ready = CSRStatus() self.prbs_config = CSRStorage(4) self.stpl_enable = CSRStorage() self.jsync = CSRStatus() self.restart_count_clear = CSR() self.restart_count = CSRStatus(8) # # # # core control/status self.comb += [ core.enable.eq(self.enable.storage), core.prbs_config.eq(self.prbs_config.storage), core.stpl_enable.eq(self.stpl_enable.storage), self.ready.status.eq(core.ready) ] self.specials += MultiReg(core.jsync, self.jsync.status) # restart monitoring # restart is a slow signal so we simply pass it to sys_clk and # count rising edges restart = Signal() restart_d = Signal() restart_count = Signal(8) self.specials += MultiReg(core.restart, restart) self.sync += \ If(self.restart_count_clear.re, restart_count.eq(0) ).Elif(restart & ~restart_d, # don't overflow when max is reached If(restart_count != (2**8-1), restart_count.eq(restart_count + 1) ) ) self.comb += self.restart_count.status.eq(restart_count)
def __init__(self, platform, **kwargs): clk_freq = int(100e6) SoCCore.__init__(self, platform, clk_freq, cpu_type=None, **kwargs) self.platform = platform self.submodules.crg = CRG(platform) self.crg.cd_sys.clk.attr.add("keep") self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(100e6)) # common led self.sys_led = Signal() self.comb += platform.request("user_led", 0).eq(self.sys_led) self.aux_led = Signal() self.comb += platform.request("user_led", 1).eq(self.aux_led) # sys led sys_counter = Signal(32) self.sync += sys_counter.eq(sys_counter + 1) self.comb += self.sys_led.eq(sys_counter[26]) sys_short_test = Signal(16) self.comb += sys_short_test.eq(sys_counter) self.comb += self.aux_led.eq(sys_short_test[15]) self.bar_led = platform.request("user_led", 2) fred = ClockDomainsRenamer("clk100")(Flintstone()) self.submodules += fred ## if this isn't here, fred isn't instantiated self.dino = Signal(16) self.yoshi = Signal(8) self.specials += MultiReg(fred.wilma, self.dino, "clk100") self.specials += MultiReg(self.dino, self.yoshi, "clk200") # this takes dino into the yoshi clock domain self.comb += self.bar_led.eq(self.yoshi[7])
def __init__(self, nchan=3, depth=8): self.valid_i = Signal() self.chan_synced = Signal() self._channels_synced = CSRStatus() lst_control = [] all_control = Signal() for i in range(nchan): name = "data_in" + str(i) data_in = Record(channel_layout, name=name) setattr(self, name, data_in) name = "data_out" + str(i) data_out = Record(channel_layout, name=name) setattr(self, name, data_out) # # # syncbuffer = _SyncBuffer(layout_len(channel_layout), depth) syncbuffer = ClockDomainsRenamer("pix")(syncbuffer) self.submodules += syncbuffer self.comb += [ syncbuffer.din.eq(data_in.raw_bits()), data_out.raw_bits().eq(syncbuffer.dout) ] is_control = Signal() self.comb += [ is_control.eq(~data_out.de), syncbuffer.re.eq(~is_control | all_control) ] lst_control.append(is_control) some_control = Signal() self.comb += [ all_control.eq(reduce(and_, lst_control)), some_control.eq(reduce(or_, lst_control)) ] self.sync.pix += \ If(~self.valid_i, self.chan_synced.eq(0) ).Else( If(some_control, If(all_control, self.chan_synced.eq(1) ).Else( self.chan_synced.eq(0) ) ) ) self.specials += MultiReg(self.chan_synced, self._channels_synced.status)
def __init__(self, pads, tuning_word): self.source = stream.Endpoint([("data", 8)]) # # # uart_clk_rxen = Signal() phase_accumulator_rx = Signal(32) rx = Signal() self.specials += MultiReg(pads.rx, rx) rx_r = Signal() rx_reg = Signal(8) rx_bitcount = Signal(4) rx_busy = Signal() rx_done = self.source.valid rx_data = self.source.data self.sync += [ rx_done.eq(0), rx_r.eq(rx), If( ~rx_busy, If( ~rx & rx_r, # look for start bit rx_busy.eq(1), rx_bitcount.eq(0), )).Else( If( uart_clk_rxen, rx_bitcount.eq(rx_bitcount + 1), If( rx_bitcount == 0, If( rx, # verify start bit rx_busy.eq(0))).Elif( rx_bitcount == 9, rx_busy.eq(0), If( rx, # verify stop bit rx_data.eq(rx_reg), rx_done.eq(1))).Else( rx_reg.eq(Cat(rx_reg[1:], rx))))) ] self.sync += \ If(rx_busy, Cat(phase_accumulator_rx, uart_clk_rxen).eq(phase_accumulator_rx + tuning_word) ).Else( Cat(phase_accumulator_rx, uart_clk_rxen).eq(2**31) )
def __init__(self, pads): self._w = CSRStorage(3, name="w") self._r = CSRStatus(1, name="r") # # # data_w = Signal() data_oe = Signal() data_r = Signal() self.comb += [ pads.mdc.eq(self._w.storage[0]), data_oe.eq(self._w.storage[1]), data_w.eq(self._w.storage[2]) ] self.specials += [ MultiReg(data_r, self._r.status[0]), Tristate(pads.mdio, data_w, data_oe, data_r) ]
def __init__(self, width, reverse=False): self.i = Signal(width) self.config = Signal(2) self.errors = Signal(32) # # # config = Signal(2) # optional bits reversing prbs_data = self.i if reverse: new_prbs_data = Signal(width) self.comb += new_prbs_data.eq(prbs_data[::-1]) prbs_data = new_prbs_data # checkers self.specials += MultiReg(self.config, config) prbs7 = PRBS7Checker(width) prbs15 = PRBS15Checker(width) prbs31 = PRBS31Checker(width) self.submodules += prbs7, prbs15, prbs31 self.comb += [ prbs7.i.eq(prbs_data), prbs15.i.eq(prbs_data), prbs31.i.eq(prbs_data) ] # errors count self.sync += \ If(config == 0, self.errors.eq(0) ).Elif(self.errors != (2**32-1), If(config == 0b01, self.errors.eq(self.errors + (prbs7.errors != 0)) ).Elif(config == 0b10, self.errors.eq(self.errors + (prbs15.errors != 0)) ).Elif(config == 0b11, self.errors.eq(self.errors + (prbs31.errors != 0)) ) )
def __init__(self, width, reverse=False): self.config = Signal(2) self.i = Signal(width) self.o = Signal(width) # # # config = Signal(2) # generators self.specials += MultiReg(self.config, config) prbs7 = PRBS7Generator(width) prbs15 = PRBS15Generator(width) prbs31 = PRBS31Generator(width) self.submodules += prbs7, prbs15, prbs31 # select prbs_data = Signal(width) self.comb += \ If(config == 0b11, prbs_data.eq(prbs31.o) ).Elif(config == 0b10, prbs_data.eq(prbs15.o) ).Else( prbs_data.eq(prbs7.o) ) # optional bits reversing if reverse: new_prbs_data = Signal(width) self.comb += new_prbs_data.eq(prbs_data[::-1]) prbs_data = new_prbs_data # prbs / data mux self.comb += \ If(config == 0, self.o.eq(self.i) ).Else( self.o.eq(prbs_data) )
def __init__(self, phys, jesd_settings, converter_data_width): self.enable = Signal() self.jsync = Signal() self.ready = Signal() self.restart = Signal() self.prbs_config = Signal(4) self.stpl_enable = Signal() self.sink = Record([("converter" + str(i), converter_data_width) for i in range(jesd_settings.nconverters)]) # # # # restart when disabled or on re-synchronization request self.comb += self.restart.eq(~self.enable | self.ready & ~self.jsync) # transport layer transport = LiteJESD204BTransportTX(jesd_settings, converter_data_width) self.submodules.transport = transport # stpl stpl = LiteJESD204BSTPLGenerator(jesd_settings, converter_data_width) self.submodules += stpl stpl_enable = Signal() self.specials += \ MultiReg(self.stpl_enable, stpl_enable) self.comb += \ If(stpl_enable, transport.sink.eq(stpl.source) ).Else( transport.sink.eq(self.sink) ) links = [] for n, (phy, lane) in enumerate(zip(phys, transport.source.flatten())): phy_name = "phy{}".format(n) phy_cd = phy_name + "_tx" # claim the phy setattr(self.submodules, phy_name, phy) ebuf = ElasticBuffer(len(phy.data), 4, "sys", phy_cd) setattr(self.submodules, "ebuf{}".format(n), ebuf) link = LiteJESD204BLinkTX(len(phy.data), jesd_settings, n) link = ClockDomainsRenamer(phy_cd)(link) links.append(link) self.comb += link.jsync.eq(self.jsync) self.submodules += link # connect data self.comb += [ ebuf.din.eq(lane), link.sink.data.eq(ebuf.dout), phy.data.eq(link.source.data), phy.ctrl.eq(link.source.ctrl) ] # connect control self.comb += phy.transmitter.init.restart.eq( self.restart & (self.prbs_config == 0)) self.specials += MultiReg(self.prbs_config, phy.transmitter.prbs_config, phy_cd) ready = Signal() self.comb += ready.eq(reduce(and_, [link.ready for link in links])) self.specials += MultiReg(ready, self.ready)
def __init__(self, sys_clk_freq, rx): self.done = Signal() self.restart = Signal() # GTH signals self.plllock = Signal() self.pllreset = Signal() self.gtXxreset = Signal() self.Xxresetdone = Signal() self.Xxdlysreset = Signal() self.Xxdlysresetdone = Signal() self.Xxphaligndone = Signal() self.Xxsyncdone = Signal() self.Xxuserrdy = Signal() # # # # Double-latch transceiver asynch outputs plllock = Signal() Xxresetdone = Signal() Xxdlysresetdone = Signal() Xxphaligndone = Signal() Xxsyncdone = Signal() self.specials += [ MultiReg(self.plllock, plllock), MultiReg(self.Xxresetdone, Xxresetdone), MultiReg(self.Xxdlysresetdone, Xxdlysresetdone), MultiReg(self.Xxphaligndone, Xxphaligndone), MultiReg(self.Xxsyncdone, Xxsyncdone) ] # 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) ] # PLL reset must be at least 2us pll_reset_cycles = ceil(2000 * sys_clk_freq / 1000000000) pll_reset_timer = WaitTimer(pll_reset_cycles) self.submodules += pll_reset_timer startup_fsm = ResetInserter()(FSM(reset_state="RESET_ALL")) self.submodules += startup_fsm ready_timer = WaitTimer(int(sys_clk_freq / 1000)) self.submodules += ready_timer self.comb += [ ready_timer.wait.eq(~self.done & ~startup_fsm.reset), startup_fsm.reset.eq(self.restart | ready_timer.done) ] if rx: cdr_stable_timer = WaitTimer(1024) self.submodules += cdr_stable_timer 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( "RESET_ALL", gtXxreset.eq(1), self.pllreset.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(plllock, NextState("RELEASE_GTH_RESET"))) # Release GTH reset and wait for GTH resetdone # (from UG476, GTH is reset on falling edge # of gtXxreset) if rx: startup_fsm.act( "RELEASE_GTH_RESET", Xxuserrdy.eq(1), cdr_stable_timer.wait.eq(1), If(Xxresetdone & cdr_stable_timer.done, NextState("ALIGN"))) else: startup_fsm.act("RELEASE_GTH_RESET", Xxuserrdy.eq(1), If(Xxresetdone, NextState("ALIGN"))) # Start delay alignment (pulse) startup_fsm.act("ALIGN", Xxuserrdy.eq(1), Xxdlysreset.eq(1), NextState("WAIT_ALIGN")) if rx: # Wait for delay alignment startup_fsm.act("WAIT_ALIGN", Xxuserrdy.eq(1), If(Xxsyncdone, NextState("READY"))) else: # Wait for delay alignment startup_fsm.act( "WAIT_ALIGN", Xxuserrdy.eq(1), If(Xxdlysresetdone, NextState("WAIT_FIRST_ALIGN_DONE"))) # Wait 2 rising edges of Xxphaligndone # (from UG576 in TX Buffer Bypass in Single-Lane Auto Mode) startup_fsm.act( "WAIT_FIRST_ALIGN_DONE", Xxuserrdy.eq(1), If(Xxphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE"))) startup_fsm.act("WAIT_SECOND_ALIGN_DONE", Xxuserrdy.eq(1), If(Xxphaligndone_rising, NextState("READY"))) startup_fsm.act("READY", Xxuserrdy.eq(1), self.done.eq(1), If(self.restart, NextState("RESET_ALL")))
def __init__(self, pads, clk_freq, fifo_depth=32, read_time=128, write_time=128): dw = len(pads.data) self.clk_freq = clk_freq # timings tRD = self.ns(30) # RD# active pulse width (t4) tRDDataSetup = self.ns(14) # RD# to DATA (t3) tWRDataSetup = self.ns(5) # DATA to WR# active setup time (t8) tWR = self.ns(30) # WR# active pulse width (t10) tMultiReg = 2 # read fifo (FTDI --> SoC) read_fifo = stream.SyncFIFO(phy_description(8), fifo_depth) # write fifo (SoC --> FTDI) write_fifo = stream.SyncFIFO(phy_description(8), fifo_depth) self.submodules += read_fifo, write_fifo # sink / source interfaces self.sink = write_fifo.sink self.source = read_fifo.source # read / write arbitration wants_write = Signal() wants_read = Signal() txe_n = Signal() rxf_n = Signal() self.specials += [ MultiReg(pads.txe_n, txe_n), MultiReg(pads.rxf_n, rxf_n) ] self.comb += [ wants_write.eq(~txe_n & write_fifo.source.valid), wants_read.eq(~rxf_n & read_fifo.sink.ready), ] read_time_en, max_read_time = anti_starvation(self, read_time) write_time_en, max_write_time = anti_starvation(self, write_time) fsm = FSM(reset_state="READ") self.submodules += fsm read_done = Signal() write_done = Signal() commuting = Signal() fsm.act( "READ", read_time_en.eq(1), If( wants_write & read_done, If(~wants_read | max_read_time, commuting.eq(1), NextState("RTW")))) fsm.act("RTW", NextState("WRITE")) fsm.act( "WRITE", write_time_en.eq(1), If( wants_read & write_done, If(~wants_write | max_write_time, commuting.eq(1), NextState("WTR")))) fsm.act("WTR", NextState("READ")) # databus tristate data_w = Signal(dw) data_r_async = Signal(dw) data_r = Signal(dw) data_oe = Signal() self.specials += [ Tristate(pads.data, data_w, data_oe, data_r_async), MultiReg(data_r_async, data_r) ] # read actions pads.rd_n.reset = 1 read_fsm = FSM(reset_state="IDLE") self.submodules += read_fsm read_counter = Signal(8) read_counter_reset = Signal() read_counter_ce = Signal() self.sync += \ If(read_counter_reset, read_counter.eq(0) ).Elif(read_counter_ce, read_counter.eq(read_counter + 1) ) read_fsm.act( "IDLE", read_done.eq(1), read_counter_reset.eq(1), If( fsm.ongoing("READ") & wants_read, If(~commuting, NextState("PULSE_RD_N")))) read_fsm.act( "PULSE_RD_N", pads.rd_n.eq(0), read_counter_ce.eq(1), If(read_counter == max((tRD - 1), (tRDDataSetup + tMultiReg - 1)), NextState("ACQUIRE_DATA"))) read_fsm.act("ACQUIRE_DATA", read_fifo.sink.valid.eq(1), read_fifo.sink.data.eq(data_r), NextState("WAIT_RXF_N")) read_fsm.act("WAIT_RXF_N", If(rxf_n, NextState("IDLE"))) # write actions pads.wr_n.reset = 1 write_fsm = FSM(reset_state="IDLE") self.submodules += write_fsm write_counter = Signal(8) write_counter_reset = Signal() write_counter_ce = Signal() self.sync += \ If(write_counter_reset, write_counter.eq(0) ).Elif(write_counter_ce, write_counter.eq(write_counter + 1) ) write_fsm.act( "IDLE", write_done.eq(1), write_counter_reset.eq(1), If( fsm.ongoing("WRITE") & wants_write, If(~commuting, NextState("SET_DATA")))) write_fsm.act( "SET_DATA", data_oe.eq(1), data_w.eq(write_fifo.source.data), write_counter_ce.eq(1), If(write_counter == (tWRDataSetup - 1), write_counter_reset.eq(1), NextState("PULSE_WR_N"))) write_fsm.act("PULSE_WR_N", data_oe.eq(1), data_w.eq(write_fifo.source.data), pads.wr_n.eq(0), write_counter_ce.eq(1), If(write_counter == (tWR - 1), NextState("WAIT_TXE_N"))) write_fsm.act( "WAIT_TXE_N", If(txe_n, write_fifo.source.ready.eq(1), NextState("IDLE")))
def __init__(self, phy): self.sink = stream.Endpoint([("data", 32)]) self.source = stream.Endpoint([("data", 32)]) self.argument = CSRStorage(32) self.command = CSRStorage(32) self.response = CSRStatus(120) self.cmdevt = CSRStatus(32) self.dataevt = CSRStatus(32) self.blocksize = CSRStorage(16) self.blockcount = CSRStorage(32) self.datatimeout = CSRStorage(32, reset=2**16) self.cmdtimeout = CSRStorage(32, reset=2**16) self.datawcrcclear = CSRStorage() self.datawcrcvalids = CSRStatus(32) self.datawcrcerrors = CSRStatus(32) # # # argument = Signal(32) command = Signal(32) response = Signal(120) cmdevt = Signal(32) dataevt = Signal(32) blocksize = Signal(16) blockcount = Signal(32) datatimeout = Signal(32) cmdtimeout = Signal(32) # sys to sd cdc self.specials += [ MultiReg(self.argument.storage, argument, "sd"), MultiReg(self.command.storage, command, "sd"), MultiReg(self.blocksize.storage, blocksize, "sd"), MultiReg(self.blockcount.storage, blockcount, "sd"), MultiReg(self.datatimeout.storage, datatimeout, "sd"), MultiReg(self.cmdtimeout.storage, cmdtimeout, "sd") ] # sd to sys cdc response_cdc = BusSynchronizer(120, "sd", "sys") cmdevt_cdc = BusSynchronizer(32, "sd", "sys") dataevt_cdc = BusSynchronizer(32, "sd", "sys") self.submodules += response_cdc, cmdevt_cdc, dataevt_cdc self.comb += [ response_cdc.i.eq(response), self.response.status.eq(response_cdc.o), cmdevt_cdc.i.eq(cmdevt), self.cmdevt.status.eq(cmdevt_cdc.o), dataevt_cdc.i.eq(dataevt), self.dataevt.status.eq(dataevt_cdc.o) ] self.submodules.new_command = PulseSynchronizer("sys", "sd") self.comb += self.new_command.i.eq(self.command.re) self.comb += [ phy.cfg.blocksize.eq(blocksize), phy.cfg.datatimeout.eq(datatimeout), phy.cfg.cmdtimeout.eq(cmdtimeout), phy.dataw.crc_clear.eq(self.datawcrcclear.storage), self.datawcrcvalids.status.eq(phy.dataw.crc_valids), self.datawcrcerrors.status.eq(phy.dataw.crc_errors) ] self.submodules.crc7inserter = ClockDomainsRenamer("sd")(CRC(9, 7, 40)) self.submodules.crc7checker = ClockDomainsRenamer("sd")(CRCChecker( 9, 7, 120)) self.submodules.crc16inserter = ClockDomainsRenamer("sd")( CRCUpstreamInserter()) self.submodules.crc16checker = ClockDomainsRenamer("sd")( CRCDownstreamChecker()) self.submodules.upstream_cdc = ClockDomainsRenamer({ "write": "sys", "read": "sd" })(stream.AsyncFIFO(self.sink.description, 4)) self.submodules.downstream_cdc = ClockDomainsRenamer({ "write": "sd", "read": "sys" })(stream.AsyncFIFO(self.source.description, 4)) self.submodules.upstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 32)], [('data', 8)], reverse=True)) self.submodules.downstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 8)], [('data', 32)], reverse=True)) self.comb += [ self.sink.connect(self.upstream_cdc.sink), self.upstream_cdc.source.connect(self.upstream_converter.sink), self.upstream_converter.source.connect(self.crc16inserter.sink), self.crc16checker.source.connect(self.downstream_converter.sink), self.downstream_converter.source.connect(self.downstream_cdc.sink), self.downstream_cdc.source.connect(self.source) ] self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM()) csel = Signal(max=6) waitresp = Signal(2) dataxfer = Signal(2) cmddone = Signal(reset=1) datadone = Signal(reset=1) blkcnt = Signal(32) pos = Signal(2) cerrtimeout = Signal() cerrcrc_en = Signal() derrtimeout = Signal() derrwrite = Signal() derrread_en = Signal() self.comb += [ waitresp.eq(command[0:2]), dataxfer.eq(command[5:7]), cmdevt.eq( Cat(cmddone, C(0, 1), cerrtimeout, cerrcrc_en & ~self.crc7checker.valid)), dataevt.eq( Cat(datadone, derrwrite, derrtimeout, derrread_en & ~self.crc16checker.valid)), self.crc7inserter.val.eq(Cat(argument, command[8:14], 1, 0)), self.crc7inserter.clr.eq(1), self.crc7inserter.enable.eq(1), self.crc7checker.val.eq(response) ] ccases = {} # To send command and CRC ccases[0] = phy.sink.data.eq(Cat(command[8:14], 1, 0)) for i in range(4): ccases[i + 1] = phy.sink.data.eq(argument[24 - 8 * i:32 - 8 * i]) ccases[5] = [ phy.sink.data.eq(Cat(1, self.crc7inserter.crc)), phy.sink.last.eq(waitresp == SDCARD_CTRL_RESPONSE_NONE) ] fsm.act( "IDLE", NextValue(pos, 0), If(self.new_command.o, NextValue(cmddone, 0), NextValue(cerrtimeout, 0), NextValue(cerrcrc_en, 0), NextValue(datadone, 0), NextValue(derrtimeout, 0), NextValue(derrwrite, 0), NextValue(derrread_en, 0), NextValue(response, 0), NextState("SEND_CMD"))) fsm.act( "SEND_CMD", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1), phy.sink.rd_wr_n.eq(0), Case(csel, ccases), If( phy.sink.valid & phy.sink.ready, If(csel < 5, NextValue(csel, csel + 1)).Else( NextValue(csel, 0), If(waitresp == SDCARD_CTRL_RESPONSE_NONE, NextValue(cmddone, 1), NextState("IDLE")).Else(NextValue(cerrcrc_en, 1), NextState("RECV_RESP"))))) fsm.act( "RECV_RESP", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1), phy.sink.rd_wr_n.eq(1), phy.sink.last.eq(dataxfer == SDCARD_CTRL_DATA_TRANSFER_NONE), If( waitresp == SDCARD_CTRL_RESPONSE_SHORT, phy.sink.data.eq(5) # (5+1)*8 == 48bits ).Elif( waitresp == SDCARD_CTRL_RESPONSE_LONG, phy.sink.data.eq(16) # (16+1)*8 == 136bits ), If( phy.source.valid, # Wait for resp or timeout coming from phy phy.source.ready.eq(1), If(phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(cerrtimeout, 1), NextValue(cmddone, 1), NextValue(datadone, 1), NextState("IDLE")).Elif( phy.source.last, # Check response CRC NextValue(self.crc7checker.check, phy.source.data[1:8]), NextValue(cmddone, 1), If(dataxfer == SDCARD_CTRL_DATA_TRANSFER_READ, NextValue(derrread_en, 1), NextState("RECV_DATA")).Elif( dataxfer == SDCARD_CTRL_DATA_TRANSFER_WRITE, NextState("SEND_DATA")).Else( NextValue(datadone, 1), NextState("IDLE")), ).Else( NextValue(response, Cat(phy.source.data, response[0:112]))))) fsm.act( "RECV_DATA", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(1), phy.sink.last.eq(blkcnt == (blockcount - 1)), phy.sink.data.eq(0), # Read 1 block If( phy.source.valid, phy.source.ready.eq(1), If( phy.source.status == SDCARD_STREAM_STATUS_OK, self.crc16checker.sink.data.eq( phy.source.data), # Manual connect streams except ctrl self.crc16checker.sink.valid.eq(phy.source.valid), self.crc16checker.sink.last.eq(phy.source.last), phy.source.ready.eq(self.crc16checker.sink.ready), If( phy.source.last & phy.source.ready, # End of block If(blkcnt < (blockcount - 1), NextValue(blkcnt, blkcnt + 1), NextState("RECV_DATA")).Else( NextValue(blkcnt, 0), NextValue(datadone, 1), NextState("IDLE")))).Elif( phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(derrtimeout, 1), NextValue(blkcnt, 0), NextValue(datadone, 1), phy.source.ready.eq(1), NextState("IDLE")))) fsm.act( "SEND_DATA", phy.sink.valid.eq(self.crc16inserter.source.valid), phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(0), phy.sink.last.eq(self.crc16inserter.source.last), phy.sink.data.eq(self.crc16inserter.source.data), self.crc16inserter.source.ready.eq(phy.sink.ready), If( self.crc16inserter.source.valid & self.crc16inserter.source.last & self.crc16inserter.source.ready, If(blkcnt < (blockcount - 1), NextValue(blkcnt, blkcnt + 1)).Else(NextValue(blkcnt, 0), NextValue(datadone, 1), NextState("IDLE"))), If( phy.source.valid, phy.source.ready.eq(1), If(phy.source.status != SDCARD_STREAM_STATUS_DATAACCEPTED, NextValue(derrwrite, 1))))
def __init__(self, cfg): self.pads = pads = _sdpads() self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8), ("status", 3)]) # # # cmdrfb_reset = Signal() self.submodules.cmdrfb = SDPHYRFB(pads.cmd.i, False) self.submodules.fifo = ClockDomainsRenamer({ "write": "sd_fb", "read": "sd" })(stream.AsyncFIFO(self.cmdrfb.source.description, 4)) self.comb += self.cmdrfb.source.connect(self.fifo.sink) ctimeout = Signal(32) cread = Signal(10) ctoread = Signal(10) cnt = Signal(8) self.submodules.fsm = fsm = ClockDomainsRenamer("sd")( FSM(reset_state="IDLE")) fsm.act( "IDLE", If(sink.valid, NextValue(ctimeout, 0), NextValue(cread, 0), NextValue(ctoread, sink.data), NextState("CMD_READSTART")).Else( cmdrfb_reset.eq(1), self.fifo.source.ready.eq(1), )) self.specials += MultiReg(cmdrfb_reset, self.cmdrfb.reset, "sd_fb") fsm.act( "CMD_READSTART", pads.cmd.oe.eq(0), pads.clk.eq(1), NextValue(ctimeout, ctimeout + 1), If(self.fifo.source.valid, NextState("CMD_READ")).Elif(ctimeout > cfg.cmdtimeout, NextState("TIMEOUT"))) fsm.act( "CMD_READ", pads.cmd.oe.eq(0), pads.clk.eq(1), source.valid.eq(self.fifo.source.valid), source.data.eq(self.fifo.source.data), source.status.eq(SDCARD_STREAM_STATUS_OK), source.last.eq(cread == ctoread), self.fifo.source.ready.eq(source.ready), If( source.valid & source.ready, NextValue(cread, cread + 1), If( cread == ctoread, If(sink.last, NextState("CMD_CLK8")).Else(sink.ready.eq(1), NextState("IDLE"))))) fsm.act( "CMD_CLK8", If(cnt < 7, NextValue(cnt, cnt + 1), pads.clk.eq(1)).Else(NextValue(cnt, 0), sink.ready.eq(1), NextState("IDLE"))) fsm.act( "TIMEOUT", source.valid.eq(1), source.data.eq(0), source.status.eq(SDCARD_STREAM_STATUS_TIMEOUT), source.last.eq(1), If(source.valid & source.ready, sink.ready.eq(1), NextState("IDLE")))
def __init__(self, platform, pads, data_width=64, bar0_size=1 * MB, cd="sys", pll1=None): self.sink = stream.Endpoint(phy_layout(data_width)) self.source = stream.Endpoint(phy_layout(data_width)) self.msi = stream.Endpoint(msi_layout()) self._lnk_up = CSRStatus() self._msi_enable = CSRStatus() self._bus_master_enable = CSRStatus() self._max_request_size = CSRStatus(16) self._max_payload_size = CSRStatus(16) self.data_width = data_width self.id = Signal(16) self.bar0_size = bar0_size self.bar0_mask = get_bar_mask(bar0_size) self.max_request_size = Signal(16) self.max_payload_size = Signal(16) # # # # clocking pcie_clk = Signal() pcie_rst = Signal() pcie_refclk = Signal() self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=pads.clk_p, i_IB=pads.clk_n, o_O=pcie_refclk) pcie_refclk.attr.add("keep") platform.add_period_constraint(pcie_refclk, 10.0) self.clock_domains.cd_pcie = ClockDomain() self.clock_domains.cd_pcie_reset_less = ClockDomain(reset_less=True) self.cd_pcie.clk.attr.add("keep") platform.add_period_constraint(self.cd_pcie.clk, 8.0) pcie_refclk_present = Signal() pcie_refclk_timer = ClockDomainsRenamer("pcie_reset_less")( WaitTimer(1024)) self.submodules += pcie_refclk_timer self.comb += [ pcie_refclk_timer.wait.eq(1), pcie_refclk_present.eq(pcie_refclk_timer.done) ] self.comb += [ self.cd_pcie.clk.eq(pcie_clk), self.cd_pcie.rst.eq(pcie_rst & pcie_refclk_present), self.cd_pcie_reset_less.clk.eq(pcie_clk), ] # tx cdc (fpga --> host) if cd == "pcie": s_axis_tx = self.sink else: tx_buffer = stream.Buffer(phy_layout(data_width)) tx_buffer = ClockDomainsRenamer(cd)(tx_buffer) tx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4) tx_cdc = ClockDomainsRenamer({"write": cd, "read": "pcie"})(tx_cdc) self.submodules += tx_buffer, tx_cdc self.comb += [ self.sink.connect(tx_buffer.sink), tx_buffer.source.connect(tx_cdc.sink) ] s_axis_tx = tx_cdc.source # rx cdc (host --> fpga) if cd == "pcie": m_axis_rx = self.source else: rx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4) rx_cdc = ClockDomainsRenamer({"write": "pcie", "read": cd})(rx_cdc) rx_buffer = stream.Buffer(phy_layout(data_width)) rx_buffer = ClockDomainsRenamer(cd)(rx_buffer) self.submodules += rx_buffer, rx_cdc self.comb += [ rx_cdc.source.connect(rx_buffer.sink), rx_buffer.source.connect(self.source) ] m_axis_rx = rx_cdc.sink # msi cdc (fpga --> host) if cd == "pcie": cfg_msi = self.msi else: msi_cdc = stream.AsyncFIFO(msi_layout(), 4) msi_cdc = ClockDomainsRenamer({ "write": cd, "read": "pcie" })(msi_cdc) self.submodules += msi_cdc self.comb += self.msi.connect(msi_cdc.sink) cfg_msi = msi_cdc.source # config def convert_size(command, size): cases = {} value = 128 for i in range(6): cases[i] = size.eq(value) value = value * 2 return Case(command, cases) lnk_up = Signal() msienable = Signal() bus_number = Signal(8) device_number = Signal(5) function_number = Signal(3) command = Signal(16) dcommand = Signal(16) self.sync.pcie += [ convert_size(dcommand[12:15], self.max_request_size), convert_size(dcommand[5:8], self.max_payload_size), self.id.eq(Cat(function_number, device_number, bus_number)) ] self.specials += [ MultiReg(lnk_up, self._lnk_up.status), MultiReg(command[2], self._bus_master_enable.status), MultiReg(msienable, self._msi_enable.status), MultiReg(self.max_request_size, self._max_request_size.status), MultiReg(self.max_payload_size, self._max_payload_size.status) ] # hard ip self.specials += Instance( "pcie_phy", p_C_DATA_WIDTH=data_width, p_C_PCIE_GT_DEVICE={ "xc7k": "GTX", "xc7a": "GTP" }[platform.device[:4]], p_C_BAR0=get_bar_mask(bar0_size), i_sys_clk=pcie_refclk, i_sys_rst_n=1 if not hasattr(pads, "rst_n") else pads.rst_n, o_pci_exp_txp=pads.tx_p, o_pci_exp_txn=pads.tx_n, i_pci_exp_rxp=pads.rx_p, i_pci_exp_rxn=pads.rx_n, o_user_clk=pcie_clk, o_user_reset=pcie_rst, o_user_lnk_up=lnk_up, #o_tx_buf_av=, #o_tx_terr_drop=, #o_tx_cfg_req=, i_tx_cfg_gnt=1, i_s_axis_tx_tvalid=s_axis_tx.valid, i_s_axis_tx_tlast=s_axis_tx.last, o_s_axis_tx_tready=s_axis_tx.ready, i_s_axis_tx_tdata=s_axis_tx.dat, i_s_axis_tx_tkeep=s_axis_tx.be, i_s_axis_tx_tuser=0, i_rx_np_ok=1, i_rx_np_req=1, o_m_axis_rx_tvalid=m_axis_rx.valid, o_m_axis_rx_tlast=m_axis_rx.last, i_m_axis_rx_tready=m_axis_rx.ready, o_m_axis_rx_tdata=m_axis_rx.dat, o_m_axis_rx_tkeep=m_axis_rx.be, #o_m_axis_rx_tuser=, #o_cfg_to_turnoff=, o_cfg_bus_number=bus_number, o_cfg_device_number=device_number, o_cfg_function_number=function_number, o_cfg_command=command, o_cfg_dcommand=dcommand, o_cfg_interrupt_msienable=msienable, i_cfg_interrupt=cfg_msi.valid, o_cfg_interrupt_rdy=cfg_msi.ready, i_cfg_interrupt_di=cfg_msi.dat, p_QPLL_PLL1_FBDIV=4 if pll1 is None else pll1.config["n2"], p_QPLL_PLL1_FBDIV_45=4 if pll1 is None else pll1.config["n1"], p_QPLL_PLL1_REFCLK_DIV=1 if pll1 is None else pll1.config["m"], i_QPLL_GTGREFCLK1=0 if pll1 is None else pll1.gtgrefclk, i_QPLL_GTREFCLK1=0 if pll1 is None else pll1.gtrefclk, i_QPLL_PLL1LOCKEN=1, i_QPLL_PLL1PD=1 if pll1 is None else 0, i_QPLL_PLL1REFCLKSEL=0b001 if pll1 is None else pll1.refclksel, i_QPLL_PLL1RESET=1 if pll1 is None else pll1.reset, o_QPLL_PLL1LOCK=Signal() if pll1 is None else pll1.lock, o_QPLL_PLL1OUTCLK=Signal() if pll1 is None else pll1.clk, o_QPLL_PLL1OUTREFCLK=Signal() if pll1 is None else pll1.refclk) litepcie_phy_path = os.path.abspath(os.path.dirname(__file__)) platform.add_source_dir( os.path.join(litepcie_phy_path, "xilinx", "7-series", "common")) if platform.device[:4] == "xc7k": platform.add_source_dir( os.path.join(litepcie_phy_path, "xilinx", "7-series", "kintex7")) elif platform.device[:4] == "xc7a": platform.add_source_dir( os.path.join(litepcie_phy_path, "xilinx", "7-series", "artix7"))
def __init__(self, pads, revision, dw=16): # Common signals self.dw = dw if dw not in [16, 32]: raise ValueError("Unsupported datawidth") # control self.tx_idle = Signal() #i self.tx_cominit_stb = Signal() #i self.tx_cominit_ack = Signal() #o self.tx_comwake_stb = Signal() #i self.tx_comwake_ack = Signal() #o self.rx_idle = Signal() #o self.rx_cdrhold = Signal() #i self.rx_cominit_stb = Signal() #o self.rx_comwake_stb = Signal() #o self.rxdisperr = Signal(dw//8) #o self.rxnotintable = Signal(dw//8) #o # datapath self.sink = stream.Endpoint(phy_description(dw)) self.source = stream.Endpoint(phy_description(dw)) # K7 specific signals # Channel - Ref Clock Ports self.gtrefclk0 = Signal() # Channel PLL self.cplllock = Signal() self.cpllreset = Signal() # Receive Ports self.rxuserrdy = Signal() # Receive Ports - 8b10b Decoder self.rxcharisk = Signal(dw//8) # Receive Ports - RX Data Path interface self.gtrxreset = Signal() self.rxdata = Signal(dw) self.rxoutclk = Signal() self.rxusrclk = Signal() self.rxusrclk2 = Signal() # Receive Ports - RX PLL Ports self.rxresetdone = Signal() self.rxdlyreset = Signal() self.rxdlyresetdone = Signal() self.rxphaligndone = Signal() # Receive Ports - RX Ports for SATA self.rxcominitdet = Signal() self.rxcomwakedet = Signal() # Transmit Ports self.txuserrdy = Signal() # Transmit Ports - 8b10b Encoder Control Ports self.txcharisk = Signal(dw//8) # Transmit Ports - TX Data Path interface self.gttxreset = Signal() self.txdata = Signal(dw) self.txoutclk = Signal() self.txusrclk = Signal() self.txusrclk2 = Signal() # Transmit Ports - TX PLL Ports self.txresetdone = Signal() self.txdlyreset = Signal() self.txdlyresetdone = Signal() self.txphaligndone = Signal() # Transmit Ports - TX Ports for PCI Express self.txelecidle = Signal(reset=1) # Transmit Ports - TX Ports for SATA self.txcomfinish = Signal() self.txcominit = Signal() self.txcomwake = Signal() # DRP port self.drpaddr = Signal(9) self.drpclk = Signal() self.drpdi = Signal(16) self.drpdo = Signal(16) self.drpen = Signal() self.drprdy = Signal() self.drpwe = Signal() # Power-down signals self.cpllpd = Signal() self.rxpd = Signal() self.txpd = Signal() # Config at startup div_config = { "sata_gen1": 4, "sata_gen2": 2, "sata_gen3": 1 } rxout_div = div_config[revision] txout_div = div_config[revision] cdr_config = { "sata_gen1": 0x0380008BFF40100008, "sata_gen2": 0x0388008BFF40200008, "sata_gen3": 0x0380008BFF10200010 } rxcdr_cfg = cdr_config[revision] # Specific / Generic signals encoding/decoding self.comb += [ self.txelecidle.eq(self.tx_idle | self.txpd), self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish), self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish), self.rx_cominit_stb.eq(self.rxcominitdet), self.rx_comwake_stb.eq(self.rxcomwakedet), ] self.submodules += [ _RisingEdge(self.tx_cominit_stb, self.txcominit), _RisingEdge(self.tx_comwake_stb, self.txcomwake), ] self.sync.sata_rx += [ self.source.valid.eq(1), self.source.charisk.eq(self.rxcharisk), self.source.data.eq(self.rxdata) ] self.sync.sata_tx += [ self.txcharisk.eq(self.sink.charisk), self.txdata.eq(self.sink.data), self.sink.ready.eq(1), ] # Internals and clock domain crossing # sys_clk --> sata_tx clk txuserrdy = Signal() txelecidle = Signal(reset=1) txcominit = Signal() txcomwake = Signal() txdlyreset = Signal() txdlyresetdone = Signal() txphaligndone = Signal() gttxreset = Signal() self.specials += [ MultiReg(self.txuserrdy, txuserrdy, "sata_tx"), MultiReg(self.txelecidle, txelecidle, "sata_tx"), MultiReg(self.gttxreset, gttxreset, "sata_tx") ] self.submodules += [ _PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"), _PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"), _PulseSynchronizer(self.txdlyreset, "sys", txdlyreset, "sata_tx") ] # sata_tx clk --> sys clk txresetdone = Signal() txcomfinish = Signal() self.specials += [ MultiReg(txresetdone, self.txresetdone, "sys"), MultiReg(txdlyresetdone, self.txdlyresetdone, "sys"), MultiReg(txphaligndone, self.txphaligndone, "sys") ] self.submodules += [ _PulseSynchronizer(txcomfinish, "sata_tx", self.txcomfinish, "sys") ] # sys clk --> sata_rx clk rxuserrdy = Signal() rxdlyreset = Signal() self.specials += [ MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx") ] self.submodules += [ _PulseSynchronizer(self.rxdlyreset, "sys", rxdlyreset, "sata_rx") ] # sata_rx clk --> sys clk rxresetdone = Signal() rxcominitdet = Signal() rxcomwakedet = Signal() rxratedone = Signal() rxdlyresetdone = Signal() rxphaligndone = Signal() rxdisperr = Signal(dw//8) rxnotintable = Signal(dw//8) self.specials += [ MultiReg(rxresetdone, self.rxresetdone, "sys"), MultiReg(rxcominitdet, self.rxcominitdet, "sys"), MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"), MultiReg(rxdlyresetdone, self.rxdlyresetdone, "sys"), MultiReg(rxphaligndone, self.rxphaligndone, "sys"), MultiReg(rxdisperr, self.rxdisperr, "sys"), MultiReg(rxnotintable, self.rxnotintable, "sys") ] # QPLL input clock self.qpllclk = Signal() self.qpllrefclk = Signal() # OOB clock (75MHz) oobclk = Signal() self.specials += \ Instance("FDPE", p_INIT=1, i_CE=1, i_PRE=0, i_C=self.gtrefclk0, i_D=~oobclk, o_Q=oobclk) # Instance gtxe2_channel_parameters = { # Simulation-Only Attributes "p_SIM_RECEIVER_DETECT_PASS": "******", "p_SIM_TX_EIDLE_DRIVE_LEVEL": "X", "p_SIM_RESET_SPEEDUP": "TRUE", "p_SIM_CPLLREFCLK_SEL": 0b001, "p_SIM_VERSION": "4.0", # RX Byte and Word Alignment Attributes "p_ALIGN_COMMA_DOUBLE": "FALSE", "p_ALIGN_COMMA_ENABLE": ones(10), "p_ALIGN_COMMA_WORD": 1, "p_ALIGN_MCOMMA_DET": "TRUE", "p_ALIGN_MCOMMA_VALUE": 0b1010000011, "p_ALIGN_PCOMMA_DET": "TRUE", "p_ALIGN_PCOMMA_VALUE": 0b0101111100, "p_SHOW_REALIGN_COMMA": "FALSE", "p_RXSLIDE_AUTO_WAIT": 7, "p_RXSLIDE_MODE": "PCS", "p_RX_SIG_VALID_DLY": 10, # RX 8B/10B Decoder Attributes "p_RX_DISPERR_SEQ_MATCH": "TRUE", "p_DEC_MCOMMA_DETECT": "TRUE", "p_DEC_PCOMMA_DETECT": "TRUE", "p_DEC_VALID_COMMA_ONLY": "FALSE", # RX Clock Correction Attributes "p_CBCC_DATA_SOURCE_SEL": "DECODED", "p_CLK_COR_SEQ_2_USE": "FALSE", "p_CLK_COR_KEEP_IDLE": "FALSE", "p_CLK_COR_MAX_LAT": 9 if dw == 16 else 19, "p_CLK_COR_MIN_LAT": 7 if dw == 16 else 15, "p_CLK_COR_PRECEDENCE": "TRUE", "p_CLK_COR_REPEAT_WAIT": 0, "p_CLK_COR_SEQ_LEN": 1, "p_CLK_COR_SEQ_1_ENABLE": ones(4), "p_CLK_COR_SEQ_1_1": 0b0100000000, "p_CLK_COR_SEQ_1_2": 0b0000000000, "p_CLK_COR_SEQ_1_3": 0b0000000000, "p_CLK_COR_SEQ_1_4": 0b0000000000, "p_CLK_CORRECT_USE": "FALSE", "p_CLK_COR_SEQ_2_ENABLE": ones(4), "p_CLK_COR_SEQ_2_1": 0b0100000000, "p_CLK_COR_SEQ_2_2": 0b0000000000, "p_CLK_COR_SEQ_2_3": 0b0000000000, "p_CLK_COR_SEQ_2_4": 0b0000000000, # RX Channel Bonding Attributes "p_CHAN_BOND_KEEP_ALIGN": "FALSE", "p_CHAN_BOND_MAX_SKEW": 1, "p_CHAN_BOND_SEQ_LEN": 1, "p_CHAN_BOND_SEQ_1_1": 0, "p_CHAN_BOND_SEQ_1_1": 0, "p_CHAN_BOND_SEQ_1_2": 0, "p_CHAN_BOND_SEQ_1_3": 0, "p_CHAN_BOND_SEQ_1_4": 0, "p_CHAN_BOND_SEQ_1_ENABLE": ones(4), "p_CHAN_BOND_SEQ_2_1": 0, "p_CHAN_BOND_SEQ_2_2": 0, "p_CHAN_BOND_SEQ_2_3": 0, "p_CHAN_BOND_SEQ_2_4": 0, "p_CHAN_BOND_SEQ_2_ENABLE": ones(4), "p_CHAN_BOND_SEQ_2_USE": "FALSE", "p_FTS_DESKEW_SEQ_ENABLE": ones(4), "p_FTS_LANE_DESKEW_CFG": ones(4), "p_FTS_LANE_DESKEW_EN": "FALSE", # RX Margin Analysis Attributes "p_ES_CONTROL": 0, "p_ES_ERRDET_EN": "FALSE", "p_ES_EYE_SCAN_EN": "TRUE", "p_ES_HORZ_OFFSET": 0, "p_ES_PMA_CFG": 0, "p_ES_PRESCALE": 0, "p_ES_QUALIFIER": 0, "p_ES_QUAL_MASK": 0, "p_ES_SDATA_MASK": 0, "p_ES_VERT_OFFSET": 0, # FPGA RX Interface Attributes "p_RX_DATA_WIDTH": 20 if dw == 16 else 40, # PMA Attributes "p_OUTREFCLK_SEL_INV": 0b11, "p_PMA_RSV": 0x00018480, "p_PMA_RSV2": 0x2050, "p_PMA_RSV3": 0, "p_PMA_RSV4": 0, "p_RX_BIAS_CFG": 0b100, "p_DMONITOR_CFG": 0xA00, "p_RX_CM_SEL": 0b11, "p_RX_CM_TRIM": 0b010, "p_RX_DEBUG_CFG": 0, "p_RX_OS_CFG": 0b10000000, "p_TERM_RCAL_CFG": 0b10000, "p_TERM_RCAL_OVRD": 0, "p_TST_RSV": 0, "p_RX_CLK25_DIV": 6, "p_TX_CLK25_DIV": 6, "p_UCODEER_CLR": 0, # PCI Express Attributes "p_PCS_PCIE_EN": "FALSE", # PCS Attributes "p_PCS_RSVD_ATTR": 0x108 if revision == "sata_gen1" else 0x100, # RX Buffer Attributes "p_RXBUF_ADDR_MODE": "FAST", "p_RXBUF_EIDLE_HI_CNT": 0b1000, "p_RXBUF_EIDLE_LO_CNT": 0b0000, "p_RXBUF_EN": "FALSE", "p_RX_BUFFER_CFG": 0, "p_RXBUF_RESET_ON_CB_CHANGE": "TRUE", "p_RXBUF_RESET_ON_COMMAALIGN": "FALSE", "p_RXBUF_RESET_ON_EIDLE": "FALSE", "p_RXBUF_RESET_ON_RATE_CHANGE": "TRUE", "p_RXBUFRESET_TIME": 1, "p_RXBUF_THRESH_OVFLW": 61, "p_RXBUF_THRESH_OVRD": "FALSE", "p_RXBUF_THRESH_UNDFLW": 4, "p_RXDLY_CFG": 0x1f, "p_RXDLY_LCFG": 0x30, "p_RXDLY_TAP_CFG": 0, "p_RXPH_CFG": 0, "p_RXPHDLY_CFG": 0x084020, "p_RXPH_MONITOR_SEL": 0, "p_RX_XCLK_SEL": "RXUSR", "p_RX_DDI_SEL": 0, "p_RX_DEFER_RESET_BUF_EN": "TRUE", # CDR Attributes "p_RXCDR_CFG": rxcdr_cfg, "p_RXCDR_FR_RESET_ON_EIDLE": 0, "p_RXCDR_HOLD_DURING_EIDLE": 0, "p_RXCDR_PH_RESET_ON_EIDLE": 0, "p_RXCDR_LOCK_CFG": 0b010101, # RX Initialization and Reset Attributes "p_RXCDRFREQRESET_TIME": 1, "p_RXCDRPHRESET_TIME": 1, "p_RXISCANRESET_TIME": 1, "p_RXPCSRESET_TIME": 1, "p_RXPMARESET_TIME": 3, # RX OOB Signaling Attributes "p_RXOOB_CFG": 0b0000110, # RX Gearbox Attributes "p_RXGEARBOX_EN": "FALSE", "p_GEARBOX_MODE": 0, # PRBS Detection Attribute "p_RXPRBS_ERR_LOOPBACK": 0, # Power-Down Attributes "p_PD_TRANS_TIME_FROM_P2": 0x03c, "p_PD_TRANS_TIME_NONE_P2": 0x3c, "p_PD_TRANS_TIME_TO_P2": 0x64, # RX OOB Signaling Attributes "p_SAS_MAX_COM": 64, "p_SAS_MIN_COM": 36, "p_SATA_BURST_SEQ_LEN": 0b0101, "p_SATA_BURST_VAL": 0b100, "p_SATA_EIDLE_VAL": 0b100, "p_SATA_MAX_BURST": 8, "p_SATA_MAX_INIT": 21, "p_SATA_MAX_WAKE": 7, "p_SATA_MIN_BURST": 4, "p_SATA_MIN_INIT": 12, "p_SATA_MIN_WAKE": 4, # RX Fabric Clock Output Control Attributes "p_TRANS_TIME_RATE": 0x0e, # TX Buffer Attributes "p_TXBUF_EN": "FALSE", "p_TXBUF_RESET_ON_RATE_CHANGE": "FALSE", "p_TXDLY_CFG": 0x1f, "p_TXDLY_LCFG": 0x030, "p_TXDLY_TAP_CFG": 0, "p_TXPH_CFG": 0x0780, "p_TXPHDLY_CFG": 0x084020, "p_TXPH_MONITOR_SEL": 0, "p_TX_XCLK_SEL": "TXUSR", # FPGA TX Interface Attributes "p_TX_DATA_WIDTH": 20 if dw ==16 else 40, # TX Configurable Driver Attributes "p_TX_DEEMPH0": 0, "p_TX_DEEMPH1": 0, "p_TX_EIDLE_ASSERT_DELAY": 0b110, "p_TX_EIDLE_DEASSERT_DELAY": 0b100, "p_TX_LOOPBACK_DRIVE_HIZ": "FALSE", "p_TX_MAINCURSOR_SEL": 0, "p_TX_DRIVE_MODE": "DIRECT", "p_TX_MARGIN_FULL_0": 0b1001110, "p_TX_MARGIN_FULL_1": 0b1001001, "p_TX_MARGIN_FULL_2": 0b1000101, "p_TX_MARGIN_FULL_3": 0b1000010, "p_TX_MARGIN_FULL_4": 0b1000000, "p_TX_MARGIN_LOW_0": 0b1000110, "p_TX_MARGIN_LOW_1": 0b1000100, "p_TX_MARGIN_LOW_2": 0b1000010, "p_TX_MARGIN_LOW_3": 0b1000000, "p_TX_MARGIN_LOW_4": 0b1000000, # TX Gearbox Attributes "p_TXGEARBOX_EN": "FALSE", # TX Initialization and Reset Attributes "p_TXPCSRESET_TIME": 1, "p_TXPMARESET_TIME": 1, # TX Receiver Detection Attributes "p_TX_RXDETECT_CFG": 0x1832, "p_TX_RXDETECT_REF": 0b100, # CPLL Attributes "p_CPLL_CFG": 0xBC07DC, "p_CPLL_FBDIV": 4, "p_CPLL_FBDIV_45": 5, "p_CPLL_INIT_CFG": 0x00001e, "p_CPLL_LOCK_CFG": 0x01e8, "p_CPLL_REFCLK_DIV": 1, "p_RXOUT_DIV": rxout_div, "p_TXOUT_DIV": txout_div, "p_SATA_CPLL_CFG": "VCO_3000MHZ", # RX Initialization and Reset Attributes "p_RXDFELPMRESET_TIME": 0b0001111, # RX Equalizer Attributes "p_RXLPM_HF_CFG": 0b00000011110000, "p_RXLPM_LF_CFG": 0b00000011110000, "p_RX_DFE_GAIN_CFG": 0x020fea, "p_RX_DFE_H2_CFG": 0b000000000000, "p_RX_DFE_H3_CFG": 0b000001000000, "p_RX_DFE_H4_CFG": 0b00011110000, "p_RX_DFE_H5_CFG": 0b00011100000, "p_RX_DFE_KL_CFG": 0b0000011111110, "p_RX_DFE_LPM_CFG": 0x0954, "p_RX_DFE_LPM_HOLD_DURING_EIDLE": 1, "p_RX_DFE_UT_CFG": 0b10001111000000000, "p_RX_DFE_VP_CFG": 0b00011111100000011, # Power-Down Attributes "p_RX_CLKMUX_PD": 1, "p_TX_CLKMUX_PD": 1, # FPGA RX Interface Attribute "p_RX_INT_DATAWIDTH": 0 if dw == 16 else 1, # FPGA TX Interface Attribute "p_TX_INT_DATAWIDTH": 0 if dw == 16 else 1, # TX Configurable Driver Attributes "p_TX_QPI_STATUS_EN": 0, # RX Equalizer Attributes "p_RX_DFE_KL_CFG2": 0b00110011000100000001100000001100, "p_RX_DFE_XYD_CFG": 0b0000000000000, # TX Configurable Driver Attributes "p_TX_PREDRIVER_MODE": 0, } self.specials += \ Instance("GTXE2_CHANNEL", # CPLL Ports #o_CPLLFBCLKLOST=, o_CPLLLOCK=self.cplllock, i_CPLLLOCKDETCLK=0, i_CPLLLOCKEN=1, i_CPLLPD=self.cpllpd, #o_CPLLREFCLKLOST=0, i_CPLLREFCLKSEL=0b001, i_CPLLRESET=self.cpllreset, i_GTRSVD=0, i_PCSRSVDIN=0, i_PCSRSVDIN2=0, i_PMARSVDIN=0, i_PMARSVDIN2=0, i_TSTIN=ones(20), #o_TSTOUT=, # Channel i_CLKRSVD=oobclk, # Channel - Clocking Ports i_GTGREFCLK=0, i_GTNORTHREFCLK0=0, i_GTNORTHREFCLK1=0, i_GTREFCLK0=self.gtrefclk0, i_GTREFCLK1=0, i_GTSOUTHREFCLK0=0, i_GTSOUTHREFCLK1=0, # Channel - DRP Ports i_DRPADDR=self.drpaddr, i_DRPCLK=self.drpclk, i_DRPDI=self.drpdi, o_DRPDO=self.drpdo, i_DRPEN=self.drpen, o_DRPRDY=self.drprdy, i_DRPWE=self.drpwe, # Clocking Ports #o_GTREFCLKMONITOR=, i_QPLLCLK=self.qpllclk, i_QPLLREFCLK=self.qpllrefclk, i_RXSYSCLKSEL=0b00, i_TXSYSCLKSEL=0b00, # Digital Monitor Ports #o_DMONITOROUT=, # FPGA TX Interface Datapath Configuration i_TX8B10BEN=1, # Loopback Ports i_LOOPBACK=0, # PCI Express Ports #o_PHYSTATUS=, i_RXRATE=0, #o_RXVALID=, # Power-Down Ports i_RXPD=Replicate(self.rxpd, 2), i_TXPD=Replicate(self.txpd, 2), # RX 8B/10B Decoder Ports i_SETERRSTATUS=0, # RX Initialization and Reset Ports i_EYESCANRESET=0, i_RXUSERRDY=rxuserrdy, # RX Margin Analysis Ports #o_EYESCANDATAERROR=, i_EYESCANMODE=0, i_EYESCANTRIGGER=0, # Receive Ports - CDR Ports i_RXCDRFREQRESET=0, i_RXCDRHOLD=self.rx_cdrhold, #o_RXCDRLOCK=, i_RXCDROVRDEN=0, i_RXCDRRESET=0, i_RXCDRRESETRSV=0, # Receive Ports - Clock Correction Ports #o_RXCLKCORCNT=, # Receive Ports - FPGA RX Interface Datapath Configuration i_RX8B10BEN=1, # Receive Ports - FPGA RX Interface Ports i_RXUSRCLK=self.rxusrclk, i_RXUSRCLK2=self.rxusrclk2, # Receive Ports - FPGA RX interface Ports o_RXDATA=self.rxdata, # Receive Ports - Pattern Checker Ports #o_RXPRBSERR=, i_RXPRBSSEL=0, # Receive Ports - Pattern Checker ports i_RXPRBSCNTRESET=0, # Receive Ports - RX Equalizer Ports i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, # Receive Ports - RX 8B/10B Decoder Ports o_RXDISPERR=rxdisperr, o_RXNOTINTABLE=rxnotintable, # Receive Ports - RX AFE i_GTXRXP=pads.rxp, i_GTXRXN=pads.rxn, # Receive Ports - RX Buffer Bypass Ports i_RXBUFRESET=0, #o_RXBUFSTATUS=, i_RXDDIEN=1, i_RXDLYBYPASS=0, i_RXDLYEN=0, i_RXDLYOVRDEN=0, i_RXDLYSRESET=rxdlyreset, o_RXDLYSRESETDONE=rxdlyresetdone, i_RXPHALIGN=0, o_RXPHALIGNDONE=rxphaligndone, i_RXPHALIGNEN=0, i_RXPHDLYPD=0, i_RXPHDLYRESET=0, #o_RXPHMONITOR=, i_RXPHOVRDEN=0, #o_RXPHSLIPMONITOR=, #o_RXSTATUS=, # Receive Ports - RX Byte and Word Alignment Ports #o_RXBYTEISALIGNED=, #o_RXBYTEREALIGN=, #o_RXCOMMADET=, i_RXCOMMADETEN=1, i_RXMCOMMAALIGNEN=1, i_RXPCOMMAALIGNEN=1, # Receive Ports - RX Channel Bonding Ports #o_RXCHANBONDSEQ=, i_RXCHBONDEN=0, i_RXCHBONDLEVEL=0, i_RXCHBONDMASTER=0, #o_RXCHBONDO=, i_RXCHBONDSLAVE=0, # Receive Ports - RX Channel Bonding Ports #o_RXCHANISALIGNED=, #o_RXCHANREALIGN=, # Receive Ports - RX Equalizer Ports i_RXDFEAGCHOLD=0, i_RXDFEAGCOVRDEN=0, i_RXDFECM1EN=0, i_RXDFELFHOLD=0, i_RXDFELFOVRDEN=0, i_RXDFELPMRESET=0, i_RXDFETAP2HOLD=0, i_RXDFETAP2OVRDEN=0, i_RXDFETAP3HOLD=0, i_RXDFETAP3OVRDEN=0, i_RXDFETAP4HOLD=0, i_RXDFETAP4OVRDEN=0, i_RXDFETAP5HOLD=0, i_RXDFETAP5OVRDEN=0, i_RXDFEUTHOLD=0, i_RXDFEUTOVRDEN=0, i_RXDFEVPHOLD=0, i_RXDFEVPOVRDEN=0, i_RXDFEVSEN=0, i_RXLPMLFKLOVRDEN=0, #o_RXMONITOROUT=, i_RXMONITORSEL=0b00, i_RXOSHOLD=0, i_RXOSOVRDEN=0, # Receive Ports - RX Equilizer Ports i_RXLPMHFHOLD=0, i_RXLPMHFOVRDEN=0, i_RXLPMLFHOLD=0, # Receive Ports - RX Fabric ClocK Output Control Ports #o_RXRATEDONE=, # Receive Ports - RX Fabric Output Control Ports o_RXOUTCLK=self.rxoutclk, #o_RXOUTCLKFABRIC=, #o_RXOUTCLKPCS=, i_RXOUTCLKSEL=0b010, # Receive Ports - RX Gearbox Ports #o_RXDATAVALID=, #o_RXHEADER=, #o_RXHEADERVALID=, #o_RXSTARTOFSEQ=, # Receive Ports - RX Gearbox Ports i_RXGEARBOXSLIP=0, # Receive Ports - RX Initialization and Reset Ports i_GTRXRESET=self.gtrxreset, i_RXOOBRESET=0, i_RXPCSRESET=0, i_RXPMARESET=0, # Receive Ports - RX Margin Analysis ports i_RXLPMEN=1, # Receive Ports - RX OOB Signaling ports #o_RXCOMSASDET=, o_RXCOMWAKEDET=rxcomwakedet, # Receive Ports - RX OOB Signaling ports o_RXCOMINITDET=rxcominitdet, # Receive Ports - RX OOB signalling Ports #o_RXELECIDLE=, i_RXELECIDLEMODE=0b00, # Receive Ports - RX Polarity Control Ports i_RXPOLARITY=0, # Receive Ports - RX gearbox ports i_RXSLIDE=0, # Receive Ports - RX8B/10B Decoder Ports #o_RXCHARISCOMMA=, o_RXCHARISK=self.rxcharisk, # Receive Ports - Rx Channel Bonding Ports i_RXCHBONDI=0, # Receive Ports -RX Initialization and Reset Ports o_RXRESETDONE=rxresetdone, # Rx AFE Ports i_RXQPIEN=0, #o_RXQPISENN=, #o_RXQPISENP=, # TX Buffer Bypass Ports i_TXPHDLYTSTCLK=0, # TX Configurable Driver Ports i_TXPOSTCURSOR=0, i_TXPOSTCURSORINV=0, i_TXPRECURSOR=0, i_TXPRECURSORINV=0, i_TXQPIBIASEN=0, i_TXQPISTRONGPDOWN=0, i_TXQPIWEAKPUP=0, # TX Initialization and Reset Ports i_CFGRESET=0, i_GTTXRESET=gttxreset, #o_PCSRSVDOUT=, i_TXUSERRDY=txuserrdy, # Transceiver Reset Mode Operation i_GTRESETSEL=0, i_RESETOVRD=0, # Transmit Ports - 8b10b Encoder Control Ports i_TXCHARDISPMODE=0, i_TXCHARDISPVAL=0, # Transmit Ports - FPGA TX Interface Ports i_TXUSRCLK=self.txusrclk, i_TXUSRCLK2=self.txusrclk2, # Transmit Ports - PCI Express Ports i_TXELECIDLE=txelecidle, i_TXMARGIN=0, i_TXRATE=0, i_TXSWING=0, # Transmit Ports - Pattern Generator Ports i_TXPRBSFORCEERR=0, # Transmit Ports - TX Buffer Bypass Ports i_TXDLYBYPASS=0, i_TXDLYEN=0, i_TXDLYHOLD=0, i_TXDLYOVRDEN=0, i_TXDLYSRESET=txdlyreset, o_TXDLYSRESETDONE=txdlyresetdone, i_TXDLYUPDOWN=0, i_TXPHALIGN=0, o_TXPHALIGNDONE=txphaligndone, i_TXPHALIGNEN=0, i_TXPHDLYPD=0, i_TXPHDLYRESET=0, i_TXPHINIT=0, #o_TXPHINITDONE=, i_TXPHOVRDEN=0, # Transmit Ports - TX Buffer Ports #o_TXBUFSTATUS=, # Transmit Ports - TX Configurable Driver Ports i_TXBUFDIFFCTRL=0b100, i_TXDEEMPH=0, i_TXDIFFCTRL=0b1000, i_TXDIFFPD=0, i_TXINHIBIT=0, i_TXMAINCURSOR=0, i_TXPISOPD=0, # Transmit Ports - TX Data Path interface i_TXDATA=self.txdata, # Transmit Ports - TX Driver and OOB signaling o_GTXTXP=pads.txp, o_GTXTXN=pads.txn, # Transmit Ports - TX Fabric Clock Output Control Ports o_TXOUTCLK=self.txoutclk, #o_TXOUTCLKFABRIC=, #o_TXOUTCLKPCS=, i_TXOUTCLKSEL=0b11, #o_TXRATEDONE=, # Transmit Ports - TX Gearbox Ports i_TXCHARISK=self.txcharisk, #o_TXGEARBOXREADY=, i_TXHEADER=0, i_TXSEQUENCE=0, i_TXSTARTSEQ=0, # Transmit Ports - TX Initialization and Reset Ports i_TXPCSRESET=0, i_TXPMARESET=0, o_TXRESETDONE=txresetdone, # Transmit Ports - TX OOB signalling Ports o_TXCOMFINISH=txcomfinish, i_TXCOMINIT=txcominit, i_TXCOMSAS=0, i_TXCOMWAKE=txcomwake, i_TXPDELECIDLEMODE=0, # Transmit Ports - TX Polarity Control Ports i_TXPOLARITY=0, # Transmit Ports - TX Receiver Detection Ports i_TXDETECTRX=0, # Transmit Ports - TX8b/10b Encoder Ports i_TX8B10BBYPASS=0, # Transmit Ports - pattern Generator Ports i_TXPRBSSEL=0, # Tx Configurable Driver Ports #o_TXQPISENN=, #o_TXQPISENP=, **gtxe2_channel_parameters )
def __init__(self, signal): self._in = CSRStatus(len(signal)) self.specials += MultiReg(signal, self._in.status)
def __init__(self, dram_port, mode="rgb", fifo_depth=512): try: dw = modes_dw[mode] except: raise ValueError("Unsupported {} video mode".format(mode)) assert dram_port.dw >= dw assert dram_port.dw == 2**log2_int(dw, need_pow2=False) self.source = source = stream.Endpoint(video_out_layout(dw)) self.underflow_enable = CSRStorage() self.underflow_update = CSR() self.underflow_counter = CSRStatus(32) # # # cd = dram_port.cd self.submodules.initiator = initiator = Initiator(cd) self.submodules.timing = timing = ClockDomainsRenamer(cd)( TimingGenerator()) self.submodules.dma = dma = ClockDomainsRenamer(cd)(DMAReader( dram_port, fifo_depth)) # ctrl path self.comb += [ # dispatch initiator parameters to timing & dma timing.sink.valid.eq(initiator.source.valid), dma.sink.valid.eq(initiator.source.valid), initiator.source.ready.eq(timing.sink.ready), # combine timing and dma source.valid.eq(timing.source.valid & (~timing.source.de | dma.source.valid)), # flush dma/timing when disabled If(~initiator.source.valid, timing.source.ready.eq(1), dma.source.ready.eq(1)).Elif( source.valid & source.ready, timing.source.ready.eq(1), dma.source.ready.eq(timing.source.de | (mode == "raw"))) ] # data path self.comb += [ # dispatch initiator parameters to timing & dma initiator.source.connect( timing.sink, keep=list_signals(frame_parameter_layout)), initiator.source.connect(dma.sink, keep=list_signals(frame_dma_layout)), # combine timing and dma source.de.eq(timing.source.de), source.hsync.eq(timing.source.hsync), source.vsync.eq(timing.source.vsync), source.data.eq(dma.source.data) ] # underflow detection underflow_enable = Signal() underflow_update = Signal() underflow_counter = Signal(32) self.specials += MultiReg(self.underflow_enable.storage, underflow_enable) underflow_update_synchronizer = PulseSynchronizer("sys", cd) self.submodules += underflow_update_synchronizer self.comb += [ underflow_update_synchronizer.i.eq(self.underflow_update.re), underflow_update.eq(underflow_update_synchronizer.o) ] sync = getattr(self.sync, cd) sync += [ If(underflow_enable, If(~source.valid, underflow_counter.eq(underflow_counter + 1))).Else( underflow_counter.eq(0)), If(underflow_update, self.underflow_counter.status.eq(underflow_counter)) ]
def __init__(self, pads, external_clocking, max_pix_clk=100e6): if external_clocking is None: self._cmd_data = CSRStorage(10) self._send_cmd_data = CSR() self._send_go = CSR() self._status = CSRStatus(4) self._max_pix_clk = CSRConstant(max_pix_clk) self.clock_domains.cd_pix = ClockDomain(reset_less=True) self._pll_reset = CSRStorage() self._pll_adr = CSRStorage(5) self._pll_dat_r = CSRStatus(16) self._pll_dat_w = CSRStorage(16) self._pll_read = CSR() self._pll_write = CSR() self._pll_drdy = CSRStatus() self.clock_domains.cd_pix2x = ClockDomain(reset_less=True) self.clock_domains.cd_pix10x = ClockDomain(reset_less=True) self.serdesstrobe = Signal() # # # # Generate 1x pixel clock clk_pix_unbuffered = Signal() pix_progdata = Signal() pix_progen = Signal() pix_progdone = Signal() pix_locked = Signal() clkfx_md_max = max(2.0 / 4.0, max_pix_clk / 50e6) self._clkfx_md_max_1000 = CSRConstant(clkfx_md_max * 1000.0) self.specials += Instance( "DCM_CLKGEN", name="hdmi_out_dcm_clkgen", # parameters p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", # reset i_FREEZEDCM=0, i_RST=ResetSignal(), # input i_CLKIN=ClockSignal("base50"), p_CLKIN_PERIOD=20.0, # output p_CLKFXDV_DIVIDE=2, p_CLKFX_MULTIPLY=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=clkfx_md_max, o_CLKFX=clk_pix_unbuffered, o_LOCKED=pix_locked, # programming interface i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen, o_PROGDONE=pix_progdone) remaining_bits = Signal(max=11) transmitting = Signal() self.comb += transmitting.eq(remaining_bits != 0) sr = Signal(10) self.sync += [ If(self._send_cmd_data.re, remaining_bits.eq(10), sr.eq(self._cmd_data.storage)).Elif( transmitting, remaining_bits.eq(remaining_bits - 1), sr.eq(sr[1:])) ] self.comb += [ pix_progdata.eq(transmitting & sr[0]), pix_progen.eq(transmitting | self._send_go.re) ] # enforce gap between commands busy_counter = Signal(max=14) busy = Signal() self.comb += busy.eq(busy_counter != 0) self.sync += If(self._send_cmd_data.re, busy_counter.eq(13)).Elif( busy, busy_counter.eq(busy_counter - 1)) mult_locked = Signal() self.comb += self._status.status.eq( Cat(busy, pix_progdone, pix_locked, mult_locked)) # Clock multiplication and buffering # Route unbuffered 1x pixel clock to PLL # Generate 1x, 2x and 10x IO pixel clocks clkfbout = Signal() pll_locked = Signal() pll0_pix10x = Signal() pll1_pix2x = Signal() pll2_pix = Signal() locked_async = Signal() pll_drdy = Signal() self.sync += If(self._pll_read.re | self._pll_write.re, self._pll_drdy.status.eq(0)).Elif( pll_drdy, self._pll_drdy.status.eq(1)) self.specials += [ Instance( "PLL_ADV", name="hdmi_out_pll_adv", p_CLKFBOUT_MULT=10, p_CLKOUT0_DIVIDE=1, # pix10x p_CLKOUT1_DIVIDE=5, # pix2x p_CLKOUT2_DIVIDE=10, # pix p_COMPENSATION="INTERNAL", i_CLKINSEL=1, i_CLKIN1=clk_pix_unbuffered, o_CLKOUT0=pll0_pix10x, o_CLKOUT1=pll1_pix2x, o_CLKOUT2=pll2_pix, o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout, o_LOCKED=pll_locked, i_RST=~pix_locked | self._pll_reset.storage, i_DADDR=self._pll_adr.storage, o_DO=self._pll_dat_r.status, i_DI=self._pll_dat_w.storage, i_DEN=self._pll_read.re | self._pll_write.re, i_DWE=self._pll_write.re, o_DRDY=pll_drdy, i_DCLK=ClockSignal()), Instance("BUFPLL", name="hdmi_out_bufpll", p_DIVIDE=5, i_PLLIN=pll0_pix10x, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked, o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe), Instance("BUFG", name="hdmi_out_pix2x_bufg", i_I=pll1_pix2x, o_O=self.cd_pix2x.clk), Instance("BUFG", name="hdmi_out_pix_bufg", i_I=pll2_pix, o_O=self.cd_pix.clk), MultiReg(locked_async, mult_locked, "sys") ] self.pll0_pix10x = pll0_pix10x self.pll1_pix2x = pll1_pix2x self.pll2_pix = pll2_pix self.pll_locked = pll_locked else: self.clock_domains.cd_pix = ClockDomain(reset_less=True) self.specials += Instance("BUFG", name="hdmi_out_pix_bufg", i_I=external_clocking.pll2_pix, o_O=self.cd_pix.clk) self.clock_domains.cd_pix2x = ClockDomain(reset_less=True) self.clock_domains.cd_pix10x = ClockDomain(reset_less=True) self.serdesstrobe = Signal() self.specials += [ Instance("BUFG", name="hdmi_out_pix2x_bufg", i_I=external_clocking.pll1_pix2x, o_O=self.cd_pix2x.clk), Instance("BUFPLL", name="hdmi_out_bufpll", p_DIVIDE=5, i_PLLIN=external_clocking.pll0_pix10x, i_GCLK=self.cd_pix2x.clk, i_LOCKED=external_clocking.pll_locked, o_IOCLK=self.cd_pix10x.clk, o_SERDESSTROBE=self.serdesstrobe), ] # Drive HDMI clock pads hdmi_clk_se = Signal() self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC", o_Q=hdmi_clk_se, i_C0=ClockSignal("pix"), i_C1=~ClockSignal("pix"), i_CE=1, i_D0=not hasattr(pads.clk_p, "inverted"), i_D1=hasattr(pads.clk_p, "inverted"), i_R=0, i_S=0) if hasattr(pads, "clk_p"): self.specials += Instance("OBUFDS", i_I=hdmi_clk_se, o_O=pads.clk_p, o_OB=pads.clk_n) else: self.comb += pads.clk.eq(hdmi_clk_se)
def __init__(self, word_width, fifo_depth): # in pix clock domain self.valid_i = Signal() self.vsync = Signal() self.de = Signal() self.r = Signal(8) self.g = Signal(8) self.b = Signal(8) # in sys clock domain word_layout = [("sof", 1), ("pixels", word_width)] self.frame = stream.Endpoint(word_layout) self.busy = Signal() self._overflow = CSR() # # # de_r = Signal() self.sync.pix += de_r.eq(self.de) rgb2ycbcr = RGB2YCbCr() self.submodules += ClockDomainsRenamer("pix")(rgb2ycbcr) chroma_downsampler = YCbCr444to422() self.submodules += ClockDomainsRenamer("pix")(chroma_downsampler) self.comb += [ rgb2ycbcr.sink.valid.eq(self.valid_i), rgb2ycbcr.sink.r.eq(self.r), rgb2ycbcr.sink.g.eq(self.g), rgb2ycbcr.sink.b.eq(self.b), rgb2ycbcr.source.connect(chroma_downsampler.sink), chroma_downsampler.source.ready.eq(1), chroma_downsampler.datapath.first.eq(self.de & ~de_r) # XXX need clean up ] # XXX need clean up de = self.de vsync = self.vsync for i in range(rgb2ycbcr.latency + chroma_downsampler.latency): next_de = Signal() next_vsync = Signal() self.sync.pix += [ next_de.eq(de), next_vsync.eq(vsync) ] de = next_de vsync = next_vsync # start of frame detection vsync_r = Signal() new_frame = Signal() self.comb += new_frame.eq(vsync & ~vsync_r) self.sync.pix += vsync_r.eq(vsync) # pack pixels into words cur_word = Signal(word_width) cur_word_valid = Signal() encoded_pixel = Signal(16) self.comb += encoded_pixel.eq(Cat(chroma_downsampler.source.y, chroma_downsampler.source.cb_cr)), pack_factor = word_width//16 assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2 pack_counter = Signal(max=pack_factor) self.sync.pix += [ cur_word_valid.eq(0), If(new_frame, cur_word_valid.eq(pack_counter == (pack_factor - 1)), pack_counter.eq(0), ).Elif(chroma_downsampler.source.valid & de, [If(pack_counter == (pack_factor-i-1), cur_word[16*i:16*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)], cur_word_valid.eq(pack_counter == (pack_factor - 1)), pack_counter.eq(pack_counter + 1) ) ] # FIFO fifo = stream.AsyncFIFO(word_layout, fifo_depth) fifo = ClockDomainsRenamer({"write": "pix", "read": "sys"})(fifo) self.submodules += fifo self.comb += [ fifo.sink.pixels.eq(cur_word), fifo.sink.valid.eq(cur_word_valid) ] self.sync.pix += \ If(new_frame, fifo.sink.sof.eq(1) ).Elif(cur_word_valid, fifo.sink.sof.eq(0) ) self.comb += [ fifo.source.connect(self.frame), self.busy.eq(0) ] # overflow detection pix_overflow = Signal() pix_overflow_reset = Signal() self.sync.pix += [ If(fifo.sink.valid & ~fifo.sink.ready, pix_overflow.eq(1) ).Elif(pix_overflow_reset, pix_overflow.eq(0) ) ] sys_overflow = Signal() self.specials += MultiReg(pix_overflow, sys_overflow) self.submodules.overflow_reset = PulseSynchronizer("sys", "pix") self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys") self.comb += [ pix_overflow_reset.eq(self.overflow_reset.o), self.overflow_reset_ack.i.eq(pix_overflow_reset) ] overflow_mask = Signal() self.comb += [ self._overflow.w.eq(sys_overflow & ~overflow_mask), self.overflow_reset.i.eq(self._overflow.re) ] self.sync += \ If(self._overflow.re, overflow_mask.eq(1) ).Elif(self.overflow_reset_ack.o, overflow_mask.eq(0) )
def __init__(self, clock_pads_or_refclk, pads, gtx, revision, clk_freq): self.tx_reset = Signal() self.rx_reset = Signal() self.ready = Signal() self.cplllock = Signal() self.clock_domains.cd_sata_tx = ClockDomain() self.clock_domains.cd_sata_rx = ClockDomain() # CPLL # (sata_gen3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps # (sata_gen2 & sata_gen1) VCO still @ 3 GHz, Line rate is # decreased with output dividers. if isinstance(clock_pads_or_refclk, Signal): self.refclk = clock_pads_or_refclk else: self.refclk = Signal() clock_pads = clock_pads_or_refclk self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=clock_pads.refclk_p, i_IB=clock_pads.refclk_n, o_O=self.refclk ) self.comb += gtx.gtrefclk0.eq(self.refclk) # TX clocking # (sata_gen3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits) / 150MHz (32-bits) # (sata_gen2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits) / 75MHz (32-bits) # (sata_gen1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits) / 37.5MHz (32-bits) mmcm_mult = 8.0 mmcm_div_config = { "sata_gen1": 16.0*gtx.dw/16, "sata_gen2": 8.0*gtx.dw/16, "sata_gen3": 4.0*gtx.dw/16 } mmcm_div = mmcm_div_config[revision] use_mmcm = mmcm_mult/mmcm_div != 1.0 if use_mmcm: mmcm_reset = Signal() mmcm_locked_async = Signal() mmcm_locked = Signal() mmcm_fb = Signal() mmcm_clk_i = Signal() mmcm_clk0_o = Signal() self.specials += [ Instance("BUFG", i_I=gtx.txoutclk, o_O=mmcm_clk_i), Instance("MMCME2_ADV", p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked_async, # DRP i_DCLK=0, i_DEN=0, i_DWE=0, #o_DRDY=, i_DADDR=0, i_DI=0, #o_DO=, # VCO p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.66667, p_CLKFBOUT_MULT_F=mmcm_mult, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1, i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb, # CLK0 p_CLKOUT0_DIVIDE_F=mmcm_div, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk0_o, ), Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk), MultiReg(mmcm_locked_async, mmcm_locked, "sys"), ] else: mmcm_locked = Signal(reset=1) mmcm_reset = Signal() self.specials += Instance("BUFG", i_I=gtx.txoutclk, o_O=self.cd_sata_tx.clk) self.comb += [ gtx.txusrclk.eq(self.cd_sata_tx.clk), gtx.txusrclk2.eq(self.cd_sata_tx.clk) ] # RX clocking # (sata_gen3) sata_rx recovered clk @ @ 300MHz (16-bits) / 150MHz (32-bits) from GTX RXOUTCLK # (sata_gen2) sata_rx recovered clk @ @ 150MHz (16-bits) / 75MHz (32-bits) from GTX RXOUTCLK # (sata_gen1) sata_rx recovered clk @ @ 75MHz (16-bits) / 37.5MHz (32-bits) from GTX RXOUTCLK self.specials += [ Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk), ] self.comb += [ gtx.rxusrclk.eq(self.cd_sata_rx.clk), gtx.rxusrclk2.eq(self.cd_sata_rx.clk) ] # Configuration Reset # After configuration, GTX's resets have to stay low for at least 500ns # See AR43482 startup_cycles = ceil(500*clk_freq/1000000000) startup_timer = WaitTimer(startup_cycles) self.submodules += startup_timer self.comb += startup_timer.wait.eq(~(self.tx_reset | self.rx_reset)) # TX Startup FSM self.tx_ready = Signal() self.tx_startup_fsm = tx_startup_fsm = ResetInserter()(FSM(reset_state="IDLE")) self.submodules += tx_startup_fsm txphaligndone = Signal(reset=1) txphaligndone_rising = Signal() self.sync += txphaligndone.eq(gtx.txphaligndone) self.comb += txphaligndone_rising.eq(gtx.txphaligndone & ~txphaligndone) # Wait 500ns of AR43482 tx_startup_fsm.act("IDLE", If(startup_timer.done, NextState("RESET_ALL") ) ) # Reset CPLL, MMCM, GTX tx_startup_fsm.act("RESET_ALL", gtx.cpllreset.eq(1), mmcm_reset.eq(1), gtx.gttxreset.eq(1), If(~self.cplllock, NextState("RELEASE_CPLL") ) ) # Release CPLL reset and wait for lock tx_startup_fsm.act("RELEASE_CPLL", mmcm_reset.eq(1), gtx.gttxreset.eq(1), If(self.cplllock, NextState("RELEASE_MMCM") ) ) # Release MMCM reset and wait for lock tx_startup_fsm.act("RELEASE_MMCM", gtx.gttxreset.eq(1), If(mmcm_locked, NextState("RELEASE_GTX") ) ) # Release GTX reset and wait for GTX resetdone # (from UG476, GTX is reseted on falling edge # of gttxreset) tx_startup_fsm.act("RELEASE_GTX", gtx.txuserrdy.eq(1), If(gtx.txresetdone, NextState("ALIGN") ) ) # Start Delay alignment (Pulse) tx_startup_fsm.act("ALIGN", gtx.txuserrdy.eq(1), gtx.txdlyreset.eq(1), NextState("WAIT_ALIGN") ) # Wait Delay alignment tx_startup_fsm.act("WAIT_ALIGN", gtx.txuserrdy.eq(1), If(gtx.txdlyresetdone, NextState("WAIT_FIRST_ALIGN_DONE") ) ) # Wait 2 rising edges of txphaligndone # (from UG476 in buffer bypass config) tx_startup_fsm.act("WAIT_FIRST_ALIGN_DONE", gtx.txuserrdy.eq(1), If(txphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE") ) ) tx_startup_fsm.act("WAIT_SECOND_ALIGN_DONE", gtx.txuserrdy.eq(1), If(txphaligndone_rising, NextState("READY") ) ) tx_startup_fsm.act("READY", gtx.txuserrdy.eq(1), self.tx_ready.eq(1) ) tx_ready_timer = WaitTimer(2*clk_freq//1000) self.submodules += tx_ready_timer self.comb += [ tx_ready_timer.wait.eq(~self.tx_ready & ~tx_startup_fsm.reset), tx_startup_fsm.reset.eq(self.tx_reset | tx_ready_timer.done), ] # RX Startup FSM self.rx_ready = Signal() self.rx_startup_fsm = rx_startup_fsm = ResetInserter()(FSM(reset_state="IDLE")) self.submodules += rx_startup_fsm cdr_stable_timer = WaitTimer(1024) self.submodules += cdr_stable_timer rxphaligndone = Signal(reset=1) rxphaligndone_rising = Signal() self.sync += rxphaligndone.eq(gtx.rxphaligndone) self.comb += rxphaligndone_rising.eq(gtx.rxphaligndone & ~rxphaligndone) # Wait 500ns of AR43482 rx_startup_fsm.act("IDLE", If(startup_timer.done, NextState("RESET_GTX") ) ) # Reset GTX rx_startup_fsm.act("RESET_GTX", gtx.gtrxreset.eq(1), If(~gtx.gttxreset, NextState("WAIT_CPLL") ) ) # Wait for CPLL lock rx_startup_fsm.act("WAIT_CPLL", gtx.gtrxreset.eq(1), If(self.cplllock, NextState("RELEASE_GTX") ) ) # Release GTX reset and wait for GTX resetdone # (from UG476, GTX is reseted on falling edge # of gttxreset) rx_startup_fsm.act("RELEASE_GTX", gtx.rxuserrdy.eq(1), cdr_stable_timer.wait.eq(1), If(gtx.rxresetdone & cdr_stable_timer.done, NextState("ALIGN") ) ) # Start Delay alignment (Pulse) rx_startup_fsm.act("ALIGN", gtx.rxuserrdy.eq(1), gtx.rxdlyreset.eq(1), NextState("WAIT_ALIGN") ) # Wait Delay alignment rx_startup_fsm.act("WAIT_ALIGN", gtx.rxuserrdy.eq(1), If(gtx.rxdlyresetdone, NextState("WAIT_FIRST_ALIGN_DONE") ) ) # Wait 2 rising edges of rxphaligndone # (from UG476 in buffer bypass config) rx_startup_fsm.act("WAIT_FIRST_ALIGN_DONE", gtx.rxuserrdy.eq(1), If(rxphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE") ) ) rx_startup_fsm.act("WAIT_SECOND_ALIGN_DONE", gtx.rxuserrdy.eq(1), If(rxphaligndone_rising, NextState("READY") ) ) rx_startup_fsm.act("READY", gtx.rxuserrdy.eq(1), self.rx_ready.eq(1) ) rx_ready_timer = WaitTimer(2*clk_freq//1000) self.submodules += rx_ready_timer self.comb += [ rx_ready_timer.wait.eq(~self.rx_ready & ~rx_startup_fsm.reset), rx_startup_fsm.reset.eq(self.rx_reset | rx_ready_timer.done), ] # Ready self.comb += self.ready.eq(self.tx_ready & self.rx_ready) # Reset for SATA TX/RX clock domains self.specials += [ AsyncResetSynchronizer(self.cd_sata_tx, ~(gtx.cplllock & mmcm_locked) | self.tx_reset), AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | self.rx_reset), MultiReg(gtx.cplllock, self.cplllock, "sys"), ]
def __init__(self, cfg): self.pads = pads = _sdpads() self.sink = sink = stream.Endpoint([("data", 8)]) self.source = source = stream.Endpoint([("data", 8), ("status", 3)]) # # # datarfb_reset = Signal() self.submodules.datarfb = SDPHYRFB(pads.data.i, True) self.submodules.cdc = ClockDomainsRenamer({ "write": "sd_fb", "read": "sd" })(stream.AsyncFIFO(self.datarfb.source.description, 4)) self.submodules.buffer = ClockDomainsRenamer("sd")(stream.Buffer( self.datarfb.source.description)) self.comb += self.datarfb.source.connect(self.buffer.sink) dtimeout = Signal(32) read = Signal(10) toread = Signal(10) cnt = Signal(8) self.submodules.fsm = fsm = ClockDomainsRenamer("sd")( FSM(reset_state="IDLE")) fsm.act( "IDLE", pads.data.oe.eq(0), pads.clk.eq(1), datarfb_reset.eq(1), self.buffer.source.ready.eq(1), If( sink.valid, NextValue(dtimeout, 0), NextValue(read, 0), # Read 1 block + 8*8 == 64 bits CRC NextValue(toread, cfg.blocksize + 8), NextState("DATA_READSTART"))) self.specials += MultiReg(datarfb_reset, self.datarfb.reset, "sd_fb") fsm.act( "DATA_READSTART", pads.data.oe.eq(0), pads.clk.eq(1), NextValue(dtimeout, dtimeout + 1), If(self.buffer.source.valid, NextState("DATA_READ")).Elif(dtimeout > cfg.datatimeout, NextState("TIMEOUT"))) fsm.act( "DATA_READ", pads.data.oe.eq(0), pads.clk.eq(1), source.valid.eq(self.buffer.source.valid), source.data.eq(self.buffer.source.data), source.status.eq(SDCARD_STREAM_STATUS_OK), source.last.eq(read == (toread - 1)), self.buffer.source.ready.eq(source.ready), If( source.valid & source.ready, NextValue(read, read + 1), If( read == (toread - 1), If(sink.last, NextState("DATA_CLK40")).Else( sink.ready.eq(1), NextState("DATA_FLUSH"))))) fsm.act( "DATA_FLUSH", pads.data.oe.eq(0), datarfb_reset.eq(1), self.buffer.source.ready.eq(1), If( cnt < 5, NextValue(cnt, cnt + 1), ).Else(NextValue(cnt, 0), NextState("IDLE"))) fsm.act( "DATA_CLK40", pads.data.oe.eq(1), pads.data.o.eq(0xf), If(cnt < 40, NextValue(cnt, cnt + 1), pads.clk.eq(1)).Else(NextValue(cnt, 0), sink.ready.eq(1), NextState("IDLE"))) fsm.act( "TIMEOUT", source.valid.eq(1), source.data.eq(0), source.status.eq(SDCARD_STREAM_STATUS_TIMEOUT), source.last.eq(1), If(source.valid & source.ready, sink.ready.eq(1), NextState("IDLE")))
def __init__(self, pll, pads, mode="master"): self.tx_data = Signal(32) self.rx_data = Signal(32) self.tx_idle = Signal() self.tx_comma = Signal() self.rx_idle = Signal() self.rx_comma = Signal() self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() self.rx_delay_ce = Signal() self.rx_delay_en_vtc = Signal() # # # self.submodules.encoder = ClockDomainsRenamer("serwb_serdes")(Encoder( 4, True)) self.decoders = [ ClockDomainsRenamer("serwb_serdes")(Decoder(True)) for _ in range(4) ] self.submodules += self.decoders # clocking: # In master mode: # - linerate/10 pll refclk provided by user # - linerate/10 slave refclk generated on clk_pads # In Slave mode: # - linerate/10 pll refclk provided by clk_pads self.clock_domains.cd_serwb_serdes = ClockDomain() self.clock_domains.cd_serwb_serdes_5x = ClockDomain() self.clock_domains.cd_serwb_serdes_20x = ClockDomain(reset_less=True) self.comb += [ self.cd_serwb_serdes.clk.eq(pll.serwb_serdes_clk), self.cd_serwb_serdes_5x.clk.eq(pll.serwb_serdes_5x_clk), self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk) ] self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes, ~pll.lock) self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst) # control/status cdc tx_idle = Signal() tx_comma = Signal() rx_idle = Signal() rx_comma = Signal() rx_bitslip_value = Signal(6) rx_delay_rst = Signal() rx_delay_inc = Signal() rx_delay_en_vtc = Signal() rx_delay_ce = Signal() self.specials += [ MultiReg(self.tx_idle, tx_idle, "serwb_serdes"), MultiReg(self.tx_comma, tx_comma, "serwb_serdes"), MultiReg(rx_idle, self.rx_idle, "sys"), MultiReg(rx_comma, self.rx_comma, "sys"), MultiReg(self.rx_bitslip_value, rx_bitslip_value, "serwb_serdes"), MultiReg(self.rx_delay_inc, rx_delay_inc, "serwb_serdes_5x"), MultiReg(self.rx_delay_en_vtc, rx_delay_en_vtc, "serwb_serdes_5x") ] self.submodules.do_rx_delay_rst = PulseSynchronizer( "sys", "serwb_serdes_5x") self.comb += [ rx_delay_rst.eq(self.do_rx_delay_rst.o), self.do_rx_delay_rst.i.eq(self.rx_delay_rst) ] self.submodules.do_rx_delay_ce = PulseSynchronizer( "sys", "serwb_serdes_5x") self.comb += [ rx_delay_ce.eq(self.do_rx_delay_ce.o), self.do_rx_delay_ce.i.eq(self.rx_delay_ce) ] # tx clock (linerate/10) if mode == "master": self.submodules.tx_clk_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | (0b1111100000 << 20) | (0b1111100000 << 10) | (0b1111100000 << 0)) clk_o = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=clk_o, i_RST=ResetSignal("serwb_serdes"), i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), i_D=self.tx_clk_gearbox.o), Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n) ] # tx datapath # tx_data -> encoders -> gearbox -> serdes self.submodules.tx_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") self.comb += [ If(tx_comma, self.encoder.k[0].eq(1), self.encoder.d[0].eq(0xbc)).Else( self.encoder.d[0].eq(self.tx_data[0:8]), self.encoder.d[1].eq(self.tx_data[8:16]), self.encoder.d[2].eq(self.tx_data[16:24]), self.encoder.d[3].eq(self.tx_data[24:32])) ] self.sync.serwb_serdes += \ If(tx_idle, self.tx_gearbox.i.eq(0) ).Else( self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)])) ) serdes_o = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=serdes_o, i_RST=ResetSignal("serwb_serdes"), i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), i_D=self.tx_gearbox.o), Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n) ] # rx clock use_bufr = True if mode == "slave": clk_i = Signal() clk_i_bufg = Signal() self.specials += [ Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i) ] if use_bufr: clk_i_bufr = Signal() self.specials += [ Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr), Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg) ] else: self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) self.comb += pll.refclk.eq(clk_i_bufg) # rx datapath # serdes -> gearbox -> bitslip -> decoders -> rx_data self.submodules.rx_gearbox = Gearbox(8, "serwb_serdes_5x", 40, "serwb_serdes") self.submodules.rx_bitslip = ClockDomainsRenamer("serwb_serdes")( BitSlip(40)) serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=pads.rx_p, i_IB=pads.rx_n, o_O=serdes_i_nodelay) ] serdes_i_delayed = Signal() serdes_q = Signal(8) self.specials += [ Instance("IDELAYE3", p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, i_CLK=ClockSignal("serwb_serdes_5x"), i_RST=rx_delay_rst, i_LOAD=0, i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc, i_CE=rx_delay_ce, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed), Instance("ISERDESE3", p_DATA_WIDTH=8, i_D=serdes_i_delayed, i_RST=ResetSignal("serwb_serdes"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, i_CLK=ClockSignal("serwb_serdes_20x"), i_CLK_B=~ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), o_Q=serdes_q) ] self.comb += [ self.rx_gearbox.i.eq(serdes_q), self.rx_bitslip.value.eq(rx_bitslip_value), self.rx_bitslip.i.eq(self.rx_gearbox.o), self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), self.rx_data.eq(Cat(*[self.decoders[i].d for i in range(4)])), rx_idle.eq(self.rx_bitslip.o == 0), rx_comma.eq( ((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) & ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0))) ]
def __init__(self, pll, pads, mode="master"): self.tx_data = Signal(32) self.rx_data = Signal(32) self.tx_idle = Signal() self.tx_comma = Signal() self.rx_idle = Signal() self.rx_comma = Signal() self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() self.rx_delay_ce = Signal() # # # self.submodules.encoder = ClockDomainsRenamer("serwb_serdes")(Encoder( 4, True)) self.decoders = [ ClockDomainsRenamer("serwb_serdes")(Decoder(True)) for _ in range(4) ] self.submodules += self.decoders # clocking: # In master mode: # - linerate/10 pll refclk provided by user # - linerate/10 slave refclk generated on clk_pads # In Slave mode: # - linerate/10 pll refclk provided by clk_pads self.clock_domains.cd_serwb_serdes = ClockDomain() self.clock_domains.cd_serwb_serdes_5x = ClockDomain() self.clock_domains.cd_serwb_serdes_20x = ClockDomain(reset_less=True) self.comb += [ self.cd_serwb_serdes.clk.eq(pll.serwb_serdes_clk), self.cd_serwb_serdes_5x.clk.eq(pll.serwb_serdes_5x_clk), self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk) ] self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes, ~pll.lock) self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst) # control/status cdc tx_idle = Signal() tx_comma = Signal() rx_idle = Signal() rx_comma = Signal() rx_bitslip_value = Signal(6) self.specials += [ MultiReg(self.tx_idle, tx_idle, "serwb_serdes"), MultiReg(self.tx_comma, tx_comma, "serwb_serdes"), MultiReg(rx_idle, self.rx_idle, "sys"), MultiReg(rx_comma, self.rx_comma, "sys") ] self.specials += MultiReg(self.rx_bitslip_value, rx_bitslip_value, "serwb_serdes"), # tx clock (linerate/10) if mode == "master": self.submodules.tx_clk_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | (0b1111100000 << 20) | (0b1111100000 << 10) | (0b1111100000 << 0)) clk_o = Signal() self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_SERDES_MODE="MASTER", o_OQ=clk_o, i_OCE=1, i_RST=ResetSignal("serwb_serdes"), i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), i_D1=self.tx_clk_gearbox.o[0], i_D2=self.tx_clk_gearbox.o[1], i_D3=self.tx_clk_gearbox.o[2], i_D4=self.tx_clk_gearbox.o[3], i_D5=self.tx_clk_gearbox.o[4], i_D6=self.tx_clk_gearbox.o[5], i_D7=self.tx_clk_gearbox.o[6], i_D8=self.tx_clk_gearbox.o[7]), Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n) ] # tx datapath # tx_data -> encoders -> gearbox -> serdes self.submodules.tx_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") self.comb += [ If(tx_comma, self.encoder.k[0].eq(1), self.encoder.d[0].eq(0xbc)).Else( self.encoder.d[0].eq(self.tx_data[0:8]), self.encoder.d[1].eq(self.tx_data[8:16]), self.encoder.d[2].eq(self.tx_data[16:24]), self.encoder.d[3].eq(self.tx_data[24:32])) ] self.sync.serwb_serdes += \ If(tx_idle, self.tx_gearbox.i.eq(0) ).Else( self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)])) ) serdes_o = Signal() self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_SERDES_MODE="MASTER", o_OQ=serdes_o, i_OCE=1, i_RST=ResetSignal("serwb_serdes"), i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), i_D1=self.tx_gearbox.o[0], i_D2=self.tx_gearbox.o[1], i_D3=self.tx_gearbox.o[2], i_D4=self.tx_gearbox.o[3], i_D5=self.tx_gearbox.o[4], i_D6=self.tx_gearbox.o[5], i_D7=self.tx_gearbox.o[6], i_D8=self.tx_gearbox.o[7]), Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n) ] # rx clock use_bufr = True if mode == "slave": clk_i = Signal() clk_i_bufg = Signal() self.specials += [ Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i) ] if use_bufr: clk_i_bufr = Signal() self.specials += [ Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr), Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg) ] else: self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) self.comb += pll.refclk.eq(clk_i_bufg) # rx datapath # serdes -> gearbox -> bitslip -> decoders -> rx_data self.submodules.rx_gearbox = Gearbox(8, "serwb_serdes_5x", 40, "serwb_serdes") self.submodules.rx_bitslip = ClockDomainsRenamer("serwb_serdes")( BitSlip(40)) serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=pads.rx_p, i_IB=pads.rx_n, o_O=serdes_i_nodelay) ] serdes_i_delayed = Signal() serdes_q = Signal(8) self.specials += [ Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, i_C=ClockSignal(), i_LD=self.rx_delay_rst, i_CE=self.rx_delay_ce, i_LDPIPEEN=0, i_INC=self.rx_delay_inc, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed), Instance("ISERDESE2", p_DATA_WIDTH=8, p_DATA_RATE="DDR", p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_IOBDELAY="IFD", i_DDLY=serdes_i_delayed, i_CE1=1, i_RST=ResetSignal("serwb_serdes"), i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKB=~ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), i_BITSLIP=0, o_Q8=serdes_q[0], o_Q7=serdes_q[1], o_Q6=serdes_q[2], o_Q5=serdes_q[3], o_Q4=serdes_q[4], o_Q3=serdes_q[5], o_Q2=serdes_q[6], o_Q1=serdes_q[7]) ] self.comb += [ self.rx_gearbox.i.eq(serdes_q), self.rx_bitslip.value.eq(rx_bitslip_value), self.rx_bitslip.i.eq(self.rx_gearbox.o), self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), self.rx_data.eq(Cat(*[self.decoders[i].d for i in range(4)])), rx_idle.eq(self.rx_bitslip.o == 0), rx_comma.eq( ((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) & ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0))) ]