def __init__(self, domain, req_stb, req_ack, req_data, srv_stb, srv_ack, srv_data): dsync = getattr(self.sync, domain) request = PulseSynchronizer("sys", domain) reply = PulseSynchronizer(domain, "sys") self.submodules += request, reply ongoing = Signal() self.comb += request.i.eq(~ongoing & req_stb) self.sync += [ req_ack.eq(reply.o), If(req_stb, ongoing.eq(1)), If(req_ack, ongoing.eq(0)) ] if req_data is not None: req_data_r = Signal.like(req_data) req_data_r.attr.add("no_retiming") self.sync += If(req_stb, req_data_r.eq(req_data)) dsync += [ If(request.o, srv_stb.eq(1)), If(srv_ack, srv_stb.eq(0)) ] if req_data is not None: dsync += If(request.o, srv_data.eq(req_data_r)) self.comb += reply.i.eq(srv_stb & srv_ack)
def __init__(self, idata): self.start = Signal() self.valid = Signal() self.error = Signal() # # # counter = Signal(2) shift = Signal() data = Signal(3) valid = Signal() error = Signal() self.submodules.fsm = fsm = ClockDomainsRenamer("sd_fb")(FSM(reset_state="IDLE")) self.sync.sd_fb += If(shift, data.eq(Cat(idata, data))) self.submodules.pulse_start = PulseSynchronizer("sd", "sd_fb") self.comb += self.pulse_start.i.eq(self.start) fsm.act("IDLE", If(self.pulse_start.o, NextState("START") ) ) fsm.act("START", If(idata == 0, NextValue(counter, 0), NextState("RECEIVE") ) ) fsm.act("RECEIVE", shift.eq(1), If(counter == 2, NextState("CHECK") ).Else( NextValue(counter, counter + 1) ) ) fsm.act("CHECK", If(data == 0b101, valid.eq(0), error.eq(1), ).Else( valid.eq(1), error.eq(0) ), NextState("IDLE") ) self.submodules.pulse_valid = PulseSynchronizer("sd_fb", "sd") self.submodules.pulse_error = PulseSynchronizer("sd_fb", "sd") self.comb += [ self.pulse_valid.i.eq(valid), self.valid.eq(self.pulse_valid.o), self.pulse_error.i.eq(error), self.error.eq(self.pulse_error.o) ]
def __init__(self, dram_port, random=True): ashift = log2_int(dram_port.dw // 8) awidth = dram_port.aw + ashift self.reset = CSR() self.start = CSR() self.base = CSRStorage(awidth) self.length = CSRStorage(awidth) self.done = CSRStatus() self.ticks = CSRStatus(32) self.errors = CSRStatus(32) # # # cd = dram_port.cd core = _LiteDRAMBISTChecker(dram_port, random) core = ClockDomainsRenamer(cd)(core) self.submodules += core reset_sync = PulseSynchronizer("sys", cd) start_sync = PulseSynchronizer("sys", cd) self.submodules += reset_sync, start_sync self.comb += [ reset_sync.i.eq(self.reset.re), core.reset.eq(reset_sync.o), start_sync.i.eq(self.start.re), core.start.eq(start_sync.o) ] done_sync = BusSynchronizer(1, cd, "sys") self.submodules += done_sync self.comb += [ done_sync.i.eq(core.done), self.done.status.eq(done_sync.o) ] base_sync = BusSynchronizer(awidth, "sys", cd) length_sync = BusSynchronizer(awidth, "sys", cd) self.submodules += base_sync, length_sync self.comb += [ base_sync.i.eq(self.base.storage), core.base.eq(base_sync.o), length_sync.i.eq(self.length.storage), core.length.eq(length_sync.o) ] ticks_sync = BusSynchronizer(32, cd, "sys") self.submodules += ticks_sync self.comb += [ ticks_sync.i.eq(core.ticks), self.ticks.status.eq(ticks_sync.o) ] errors_sync = BusSynchronizer(32, cd, "sys") self.submodules += errors_sync self.comb += [ errors_sync.i.eq(core.errors), self.errors.status.eq(errors_sync.o) ]
def __init__(self, platform): # instantiate the clock module crg = CRG(platform, sim_config) self.submodules += crg # instantiate the DUT pulse_in = Signal() pulse_out = Signal() self.submodules.pulsesync = PulseSynchronizer("sys", "adc") self.comb += self.pulsesync.i.eq(pulse_in) self.comb += pulse_out.eq(self.pulsesync.o) # connect test vectors to DUT mult = Signal(4) # allow each element in pulse_vect to be repeated "mult" times count = Signal(4) # counter variable to implement mult self.comb += mult.eq(5) # in this case, 5 index = Signal(4) # tracks the index of the vector we are in self.sync.sys += [ # generate vector index based on count/multiply params count.eq(count + 1), If(count == mult, index.eq(index + 1), count.eq(0), ) ] # now assign vector to DUT signal(s) for k, i in enumerate(pulse_vect): self.sync.sys += [ If( (count == 0) & (k == index), pulse_in.eq(i) ) ]
def __init__(self, period_bits=24): self.data = Signal(10) self._update = CSR() self._value = CSRStatus(period_bits) ### # (pipeline stage 1) # We ignore the 10th (inversion) bit, as it is independent of the # transition minimization. data_r = Signal(9) self.sync.pix += data_r.eq(self.data[:9]) # (pipeline stage 2) # Count the number of transitions in the TMDS word. transitions = Signal(8) self.comb += [ transitions[i].eq(data_r[i] ^ data_r[i + 1]) for i in range(8) ] transition_count = Signal(max=9) self.sync.pix += transition_count.eq( optree("+", [transitions[i] for i in range(8)])) # Control data characters are designed to have a large number (7) of # transitions to help the receiver synchronize its clock with the # transmitter clock. is_control = Signal() self.sync.pix += is_control.eq( optree("|", [data_r == ct for ct in control_tokens])) # (pipeline stage 3) # The TMDS characters selected to represent pixel data contain five or # fewer transitions. is_error = Signal() self.sync.pix += is_error.eq((transition_count > 4) & ~is_control) # counter period_counter = Signal(period_bits) period_done = Signal() self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1) wer_counter = Signal(period_bits) wer_counter_r = Signal(period_bits) wer_counter_r_updated = Signal() self.sync.pix += [ wer_counter_r_updated.eq(period_done), If(period_done, wer_counter_r.eq(wer_counter), wer_counter.eq(0)).Elif(is_error, wer_counter.eq(wer_counter + 1)) ] # sync to system clock domain wer_counter_sys = Signal(period_bits) self.submodules.ps_counter = PulseSynchronizer("pix", "sys") self.comb += self.ps_counter.i.eq(wer_counter_r_updated) self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r)) # register interface self.sync += If(self._update.re, self._value.status.eq(wer_counter_sys))
def __init__(self, comma, sys_clk_freq, check_period=6e-3): self.rxdata = Signal(20) self.restart = Signal() check_max_val = ceil(check_period*sys_clk_freq) check_counter = Signal(max=check_max_val+1) check = Signal() self.sync += [ check.eq(0), If(check_counter == 0, check.eq(1), check_counter.eq(check_max_val) ).Else( check_counter.eq(check_counter-1) ) ] comma_n = ~comma & 0b1111111111 comma_seen_rxclk = Signal() comma_seen = Signal() self.specials += MultiReg(comma_seen_rxclk, comma_seen) comma_seen_reset = PulseSynchronizer("sys", "rx") self.submodules += comma_seen_reset self.sync.rx += \ If(comma_seen_reset.o, comma_seen_rxclk.eq(0) ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), comma_seen_rxclk.eq(1) ) self.comb += \ If(check, If(~comma_seen, self.restart.eq(1)), comma_seen_reset.i.eq(1) )
def __init__(self, with_csr=True, simulation=False): self.addr = Signal(5) self.data = Signal(32) self.send = Signal() self.done = Signal() # # # # Create slow icap clk (sys_clk/16) --------------------------------------------------------- self.clock_domains.cd_icap = ClockDomain() icap_clk_counter = Signal(4) self.sync += icap_clk_counter.eq(icap_clk_counter + 1) self.sync += self.cd_icap.clk.eq(icap_clk_counter[3]) # Resynchronize send pulse to icap domain --------------------------------------------------- ps_send = PulseSynchronizer("sys", "icap") self.submodules += ps_send self.comb += ps_send.i.eq(self.send) # Generate icap bitstream write sequence self._csib = _csib = Signal(reset=1) self._i = _i = Signal(32) _addr = self.addr << 13 _data = self.data self.sync.icap += [ _i.eq(0xffffffff), # dummy timeline( ps_send.o, [ (1, [_csib.eq(1), self.done.eq(0)]), (2, [_csib.eq(0), _i.eq(0x20000000)]), # noop (3, [_csib.eq(0), _i.eq(0xaa995566)]), # sync word (4, [_csib.eq(0), _i.eq(0x20000000)]), # noop (5, [_csib.eq(0), _i.eq(0x20000000)]), # noop (6, [_csib.eq(0), _i.eq(0x30000001 | _addr) ]), # write command (7, [_csib.eq(0), _i.eq(_data)]), # write value (8, [_csib.eq(0), _i.eq(0x20000000)]), # noop (9, [_csib.eq(0), _i.eq(0x20000000)]), # noop (10, [_csib.eq(0), _i.eq(0x30008001) ]), # write to cmd register (11, [_csib.eq(0), _i.eq(0x0000000d)]), # desync command (12, [_csib.eq(0), _i.eq(0x20000000)]), # noop (13, [_csib.eq(0), _i.eq(0x20000000)]), # noop (14, [_csib.eq(1), self.done.eq(1)]), ]) ] # ICAP instance if not simulation: self.specials += [ Instance( "ICAPE2", p_ICAP_WIDTH="X32", i_CLK=ClockSignal("icap"), i_CSIB=_csib, i_RDWRB=0, i_I=Cat(*[_i[8 * i:8 * (i + 1)][::-1] for i in range(4)]), ) ]
def __init__(self, clk_freq): self.mode = Signal() self._mode = CSRStatus() # # # mode = Signal() update_mode = Signal() self.sync += \ If(update_mode, self.mode.eq(mode) ) self.comb += self._mode.status.eq(self.mode) # Principle: # sys_clk >= 125MHz # eth_rx <= 125Mhz # We generate ticks every 1024 clock cycles in eth_rx domain # and measure ticks period in sys_clk domain. # Generate a tick every 1024 clock cycles (eth_rx clock domain) eth_tick = Signal() eth_counter = Signal(10, reset_less=True) self.sync.eth_rx += eth_counter.eq(eth_counter + 1) self.comb += eth_tick.eq(eth_counter == 0) # Synchronize tick (sys clock domain) sys_tick = Signal() eth_ps = PulseSynchronizer("eth_rx", "sys") self.comb += [eth_ps.i.eq(eth_tick), sys_tick.eq(eth_ps.o)] self.submodules += eth_ps # sys_clk domain counter sys_counter = Signal(24, reset_less=True) sys_counter_reset = Signal() sys_counter_ce = Signal() self.sync += [ If(sys_counter_reset, sys_counter.eq(0)).Elif(sys_counter_ce, sys_counter.eq(sys_counter + 1)) ] fsm = FSM(reset_state="IDLE") self.submodules += fsm fsm.act("IDLE", sys_counter_reset.eq(1), If(sys_tick, NextState("COUNT"))) fsm.act("COUNT", sys_counter_ce.eq(1), If(sys_tick, NextState("DETECTION"))) fsm.act( "DETECTION", update_mode.eq(1), # if freq < 125MHz-5% use MII mode If(sys_counter > int((clk_freq / 125000000) * 1024 * 1.05), mode.eq(1) # if freq >= 125MHz-5% use GMII mode ).Else(mode.eq(0)), NextState("IDLE"))
def cdc(i): o = Signal() psync = PulseSynchronizer("sys", "sys2x") self.submodules += psync self.comb += [ psync.i.eq(i), o.eq(psync.o), ] return o
def csr_cdc(self, i): o = Signal() psync = PulseSynchronizer("sys", self.internal_cd) self.submodules += psync self.comb += [ psync.i.eq(i), o.eq(psync.o), ] return o
def __init__(self, period_bits=24): self.data = Signal(10) self._update = CSR() self._value = CSRStatus(period_bits) ### # pipeline stage 1 # we ignore the 10th (inversion) bit, as it is independent of the transition minimization data_r = Signal(9) self.sync.pix += data_r.eq(self.data[:9]) # pipeline stage 2 transitions = Signal(8) self.comb += [ transitions[i].eq(data_r[i] ^ data_r[i + 1]) for i in range(8) ] transition_count = Signal(max=9) self.sync.pix += transition_count.eq( reduce(add, [transitions[i] for i in range(8)])) is_control = Signal() self.sync.pix += is_control.eq( reduce(or_, [data_r == ct for ct in control_tokens])) # pipeline stage 3 is_error = Signal() self.sync.pix += is_error.eq((transition_count > 4) & ~is_control) # counter period_counter = Signal(period_bits) period_done = Signal() self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1) wer_counter = Signal(period_bits) wer_counter_r = Signal(period_bits) wer_counter_r_updated = Signal() self.sync.pix += [ wer_counter_r_updated.eq(period_done), If(period_done, wer_counter_r.eq(wer_counter), wer_counter.eq(0)).Elif(is_error, wer_counter.eq(wer_counter + 1)) ] # sync to system clock domain wer_counter_sys = Signal(period_bits) self.submodules.ps_counter = PulseSynchronizer("pix", "sys") self.comb += self.ps_counter.i.eq(wer_counter_r_updated) self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r)) # register interface self.sync += If(self._update.re, self._value.status.eq(wer_counter_sys))
def add_preamble(self): rx_preamble = preamble.LiteEthMACPreambleChecker(datapath_dw) rx_preamble = ClockDomainsRenamer(cd_rx)(rx_preamble) self.submodules += rx_preamble self.pipeline.append(rx_preamble) ps = PulseSynchronizer(cd_rx, "sys") self.submodules += ps self.comb += ps.i.eq(rx_preamble.error) self.sync += If( ps.o, self.preamble_errors.status.eq( self.preamble_errors.status + 1))
def __init__(self, domain, emi_stb, emi_data, rec_stb, rec_ack, rec_data): emi_data_r = Signal.like(emi_data) emi_data_r.attr.add("no_retiming") dsync = getattr(self.sync, domain) dsync += If(emi_stb, emi_data_r.eq(emi_data)) ps = PulseSynchronizer(domain, "sys") self.submodules += ps self.comb += ps.i.eq(emi_stb) self.sync += [ If(rec_ack, rec_stb.eq(0)), If(ps.o, rec_data.eq(emi_data_r), rec_stb.eq(1)) ]
def create_insert_logic(self): self.arm = Signal() self.pending = Signal() self.data = Signal.like(self.target) buf = Signal.like(self.target) buf.attr.add("no_retiming") self.specials += MultiReg(buf, self.data, "microscope") ps_arm = PulseSynchronizer("microscope", self.clock_domain) ps_done = PulseSynchronizer(self.clock_domain, "microscope") self.submodules += ps_arm, ps_done self.comb += ps_arm.i.eq(self.arm) self.sync.microscope += [ If(ps_done.o, self.pending.eq(0)), If(self.arm, self.pending.eq(1)) ] sync = getattr(self.sync, self.clock_domain) sync += [ ps_done.i.eq(0), If(ps_arm.o, buf.eq(self.target), ps_done.i.eq(1)) ]
def add_crc(self): rx_crc = crc.LiteEthMACCRC32Checker( eth_phy_description(datapath_dw)) rx_crc = BufferizeEndpoints({"sink": DIR_SINK})( rx_crc) # FIXME: Still required? rx_crc = ClockDomainsRenamer(cd_rx)(rx_crc) self.submodules += rx_crc self.pipeline.append(rx_crc) ps = PulseSynchronizer(cd_rx, "sys") self.submodules += ps self.comb += ps.i.eq(rx_crc.error), self.sync += If( ps.o, self.crc_errors.status.eq(self.crc_errors.status + 1))
def create_insert_logic(self): self.arm = Signal() self.pending = Signal() self.address = Signal(max=self.depth) self.data = Signal(len(self.target)) self.specials.memory = Memory(len(self.target), self.depth) rdport = self.memory.get_port(clock_domain="microscope") self.specials += rdport self.comb += [rdport.adr.eq(self.address), self.data.eq(rdport.dat_r)] ps_arm = PulseSynchronizer("microscope", self.clock_domain) ps_done = PulseSynchronizer(self.clock_domain, "microscope") self.submodules += ps_arm, ps_done self.comb += ps_arm.i.eq(self.arm) self.sync.microscope += [ If(ps_done.o, self.pending.eq(0)), If(self.arm, self.pending.eq(1)) ] port = self.memory.get_port(write_capable=True, clock_domain=self.clock_domain) self.specials += port running = Signal() wait_trigger = Signal() sync = getattr(self.sync, self.clock_domain) sync += [ ps_done.i.eq(0), If(running, port.adr.eq(port.adr + 1), If(port.adr == self.depth - 1, running.eq(0), ps_done.i.eq(1))), If(wait_trigger & self.trigger, running.eq(1), wait_trigger.eq(0)), If(ps_arm.o, wait_trigger.eq(1)) ] self.comb += port.we.eq(running) sync += port.dat_w.eq(self.target)
def _register_trigger_in(self, signal, label, cd="rio_phy"): if isinstance(cd, str): cd = cd elif isinstance(cd, ClockDomain): cd = cd.name else: raise ValueError("Invalid clock domain") if cd == "rio_phy": trigger_in_rio_phy = signal else: trigger_in_rio_phy = Signal() cdc = PulseSynchronizer(cd, "rio_phy") self.submodules += cdc self.comb += [cdc.i.eq(signal), trigger_in_rio_phy.eq(cdc.o)] self.trigger_in_signals.append(trigger_in_rio_phy) self.trigger_in_labels.append(label)
def csr_helper(obj, name, regs, cdc=False, pulsed=False, **kwargs): ''' handle csr + optional clock domain crossing (cdc) from sys to sample obj: the object where the csr will be pushed into cdc: add a pulse synchronizer to move the csr write strobe to the sample domain, then use the strobe to latch csr.storage pulsed: instead of latching csr.storage in the sample clock domain, make its value valid only for one cycle and zero otherwise ''' if type(regs) not in (list, tuple): regs = [regs] for i, reg in enumerate(regs): name_ = name if len(regs) > 1: name_ += str(i) if 'reset' not in kwargs: try: kwargs['reset'] = reg.reset except AttributeError: print('csr_helper(): could not extract reset value from', name_, reg) csr = CSRStorage(len(reg), name=name_, **kwargs) print('CSR: {} len({}) reset({})'.format(csr.name, len(csr.storage), csr.storage.reset.value)) setattr(obj, name_, csr) if cdc: # csr.storage is fully latched and stable when csr.re is pulsed # hence we only need to cross the csr.re pulse into the sample # clock domain and then latch csr.storage there once more ps = PulseSynchronizer('sys', 'sample') setattr(obj.submodules, name_ + '_sync', ps) obj.comb += ps.i.eq(csr.re) if pulsed: obj.sync.sample += reg.eq(Mux(ps.o, csr.storage, 0)) else: obj.sync.sample += If(ps.o, reg.eq(csr.storage)) else: if pulsed: obj.comb += reg.eq(Mux(csr.re, csr.storage, 0)) else: obj.comb += reg.eq(csr.storage)
def __init__(self, roi_engines): counts_in = [roi_engine.out.count for roi_engine in roi_engines] # This assumes all ROI engines update at the same time. self.update = Signal() # stays valid until the next frame after self.update is pulsed. self.counts = [Signal.like(count) for count in counts_in] # # # for count in counts_in: count.attr.add("no_retiming") counts_rtio = [Signal.like(count) for count in counts_in] self.specials += [MultiReg(i, o, "rtio") for i, o in zip(counts_in, self.counts)] ps = PulseSynchronizer("cl", "rtio") self.submodules += ps self.comb += ps.i.eq(roi_engines[0].out.update) self.sync.rtio += self.update.eq(ps.o)
def __init__(self, width, depth, port, **kwargs): self.adc_data = adc_data = Signal(width) acq_start, acq_start_x = Signal(reset=0), Signal(reset=0) self._buf_full = CSRStatus( fields=[CSRField("acq_complete", size=1, offset=0)]) self._acq_start = CSRStorage( fields=[CSRField("acq_start", size=1, offset=0, pulse=True)]) w_addr = Signal(16, reset=0) self.comb += [ self._buf_full.fields.acq_complete.eq(w_addr == depth), acq_start.eq(self._acq_start.fields.acq_start), port.adr.eq(w_addr), port.dat_w.eq(adc_data), port.we.eq(w_addr != depth) ] self.submodules.ps = PulseSynchronizer("sys", "sample") self.comb += [self.ps.i.eq(acq_start), acq_start_x.eq(self.ps.o)] self.sync.sample += [ If(acq_start_x & (w_addr == depth), w_addr.eq(0)).Elif(w_addr != depth, w_addr.eq(w_addr + 1)) ]
def __init__(self, dma): self.enable = CSRStorage() self.slot0_base = CSRStorage(32) self.slot1_base = CSRStorage(32) self.length = CSRStorage(32) self.start = CSR() self.idle = CSRStatus() self.slot = CSRStatus() # # # self.specials += [ MultiReg(self.enable.storage, dma.enable, dma.cd), MultiReg(self.slot0_base.storage, dma.slot0_base, dma.cd), MultiReg(self.slot1_base.storage, dma.slot1_base, dma.cd), MultiReg(self.length.storage, dma.length, dma.cd), MultiReg(dma.idle, self.idle.status), MultiReg(dma.slot, self.slot.status), ] start_sync = PulseSynchronizer("sys", dma.cd) self.submodules += start_sync self.comb += [ start_sync.i.eq(self.start.re), dma.start.eq(start_sync.o) ] if hasattr(dma, "source"): self.underflows = CSRStatus(32) self.sync.pix += [ If(~dma.source.valid, self.underflows.status.eq(self.underflows.status + 1)) ] if hasattr(dma, "sink"): self.overflows = CSRStatus(32) self.sync.pix += [ If(~dma.sink.ready, self.overflows.status.eq(self.overflows.status + 1)) ]
def __init__(self, counter, input_signal): self.arm = CSR() self.tag = CSRStatus(len(counter)) # in helper clock domain self.h_tag = Signal(len(counter)) self.h_tag_update = Signal() # # # deglitcher = DDMTDDeglitcherFirstEdge(input_signal) self.submodules += deglitcher self.sync.helper += [ self.h_tag_update.eq(0), If(deglitcher.detect, self.h_tag_update.eq(1), self.h_tag.eq(counter + deglitcher.tag_correction)) ] tag_update_ps = PulseSynchronizer("helper", "sys") self.submodules += tag_update_ps self.comb += tag_update_ps.i.eq(self.h_tag_update) tag_update = Signal() self.sync += tag_update.eq(tag_update_ps.o) tag = Signal(len(counter)) self.h_tag.attr.add("no_retiming") self.specials += MultiReg(self.h_tag, tag) self.sync += [ If(self.arm.re & self.arm.r, self.arm.w.eq(1)), If( tag_update, If(self.arm.w, self.tag.status.eq(tag)), self.arm.w.eq(0), ) ]
def __init__(self, endpoint, count_width=32, clock_domain="sys", with_tokens=False, with_overflows=False, with_underflows=False): self.reset = CSR() self.latch = CSR() if with_tokens: self.tokens = CSRStatus(count_width) if with_overflows: self.overflows = CSRStatus(count_width) if with_underflows: self.underflows = CSRStatus(count_width) # # # reset = Signal() latch = Signal() if clock_domain == "sys": self.comb += reset.eq(self.reset.re) self.comb += latch.eq(self.latch.re) else: reset_ps = PulseSynchronizer("sys", clock_domain) latch_ps = PulseSynchronizer("sys", clock_domain) self.submodules += reset_ps, latch_ps self.comb += reset_ps.i.eq(self.reset.re) self.comb += reset.eq(reset_ps.o) self.comb += latch_ps.i.eq(self.latch.re) self.comb += latch.eq(latch_ps.o) # Generic Monitor Counter ------------------------------------------------------------------ class MonitorCounter(Module): def __init__(self, reset, latch, enable, count): _count = Signal.like(count) _count_latched = Signal.like(count) _sync = getattr(self.sync, clock_domain) _sync += [ If( reset, _count.eq(0), _count_latched.eq(0), ).Elif( enable, If(_count != (2**len(count) - 1), _count.eq(_count + 1))), If(latch, _count_latched.eq(_count)) ] self.specials += MultiReg(_count_latched, count) # Tokens Count ----------------------------------------------------------------------------- if with_tokens: tokens_counter = MonitorCounter(reset, latch, endpoint.valid & endpoint.ready, self.tokens.status) self.submodules += token_counter # Overflows Count (only useful when endpoint is expected to always be ready) --------------- if with_overflows: overflow_counter = MonitorCounter(reset, latch, endpoint.valid & ~endpoint.ready, self.overflows.status) self.submodules += overflow_counter # Underflows Count (only useful when endpoint is expected to always be valid) -------------- if with_underflows: underflow_counter = MonitorCounter( reset, latch, ~endpoint.valid & endpoint.ready, self.underflows.status) self.submodules += underflow_counter
def __init__(self, refclk_or_clk_pads, data_pads, sys_clk_freq): pcs = PCS(lsb_first=True) self.submodules += pcs self.sink = pcs.sink self.source = pcs.source self.link_up = pcs.link_up self.clock_domains.cd_eth_tx = ClockDomain() self.clock_domains.cd_eth_rx = ClockDomain() self.clock_domains.cd_eth_tx_half = ClockDomain(reset_less=True) self.clock_domains.cd_eth_rx_half = ClockDomain(reset_less=True) # for specifying clock constraints. 62.5MHz clocks. self.txoutclk = Signal() self.rxoutclk = Signal() # # # if isinstance(refclk_or_clk_pads, Signal): refclk = refclk_or_clk_pads else: refclk = Signal() self.specials += Instance("IBUFDS_GTE2", i_I=refclk_or_clk_pads.p, i_IB=refclk_or_clk_pads.n, i_CEB=0, o_O=refclk) # GTX transceiver tx_reset = Signal() tx_mmcm_locked = Signal() tx_data = Signal(20) tx_reset_done = Signal() rx_reset = Signal() rx_mmcm_locked = Signal() rx_data = Signal(20) rx_reset_done = Signal() pll = GTXChannelPLL(refclk, 200e6, 1.25e9) self.submodules.pll = pll # Work around Python's 255 argument limitation. gtx_params = dict( # Simulation-Only Attributes p_SIM_RECEIVER_DETECT_PASS="******", p_SIM_TX_EIDLE_DRIVE_LEVEL="X", p_SIM_RESET_SPEEDUP="FALSE", p_SIM_CPLLREFCLK_SEL="FALSE", p_SIM_VERSION="4.0", # RX Byte and Word Alignment Attributes p_ALIGN_COMMA_DOUBLE="FALSE", p_ALIGN_COMMA_ENABLE=0b1111111111, p_ALIGN_COMMA_WORD=2, p_ALIGN_MCOMMA_DET="TRUE", p_ALIGN_MCOMMA_VALUE=0b1010000011, p_ALIGN_PCOMMA_DET="TRUE", p_ALIGN_PCOMMA_VALUE=0b0101111100, p_SHOW_REALIGN_COMMA="TRUE", p_RXSLIDE_AUTO_WAIT=7, p_RXSLIDE_MODE="OFF", 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="TRUE", # 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, p_CLK_COR_MIN_LAT=7, p_CLK_COR_PRECEDENCE="TRUE", p_CLK_COR_REPEAT_WAIT=0, p_CLK_COR_SEQ_LEN=1, p_CLK_COR_SEQ_1_ENABLE=0b1111, 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=0b1111, 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=0b0000000000, p_CHAN_BOND_SEQ_1_2=0b0000000000, p_CHAN_BOND_SEQ_1_3=0b0000000000, p_CHAN_BOND_SEQ_1_4=0b0000000000, p_CHAN_BOND_SEQ_1_ENABLE=0b1111, p_CHAN_BOND_SEQ_2_1=0b0000000000, p_CHAN_BOND_SEQ_2_2=0b0000000000, p_CHAN_BOND_SEQ_2_3=0b0000000000, p_CHAN_BOND_SEQ_2_4=0b0000000000, p_CHAN_BOND_SEQ_2_ENABLE=0b1111, p_CHAN_BOND_SEQ_2_USE="FALSE", p_FTS_DESKEW_SEQ_ENABLE=0b1111, p_FTS_LANE_DESKEW_CFG=0b1111, p_FTS_LANE_DESKEW_EN="FALSE", # RX Margin Analysis Attributes p_ES_CONTROL=0b000000, p_ES_ERRDET_EN="FALSE", p_ES_EYE_SCAN_EN="TRUE", p_ES_HORZ_OFFSET=0x000, p_ES_PMA_CFG=0b0000000000, p_ES_PRESCALE=0b00000, p_ES_QUALIFIER=0x00000000000000000000, p_ES_QUAL_MASK=0x00000000000000000000, p_ES_SDATA_MASK=0x00000000000000000000, p_ES_VERT_OFFSET=0b000000000, # FPGA RX Interface Attributes p_RX_DATA_WIDTH=20, # PMA Attributes p_OUTREFCLK_SEL_INV=0b11, p_PMA_RSV=0x001e7080, p_PMA_RSV2=0x2050, p_PMA_RSV3=0b00, p_PMA_RSV4=0x00000000, p_RX_BIAS_CFG=0b000000000100, p_DMONITOR_CFG=0x000A00, p_RX_CM_SEL=0b11, p_RX_CM_TRIM=0b010, p_RX_DEBUG_CFG=0b000000000000, p_RX_OS_CFG=0b0000010000000, p_TERM_RCAL_CFG=0b10000, p_TERM_RCAL_OVRD=0b0, p_TST_RSV=0x00000000, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, p_UCODEER_CLR=0b0, # PCI Express Attributes p_PCS_PCIE_EN="FALSE", # PCS Attributes p_PCS_RSVD_ATTR=0x000000000000, # RX Buffer Attributes p_RXBUF_ADDR_MODE="FAST", p_RXBUF_EIDLE_HI_CNT=0b1000, p_RXBUF_EIDLE_LO_CNT=0b0000, p_RXBUF_EN="TRUE", p_RX_BUFFER_CFG=0b000000, 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=0b00001, p_RXBUF_THRESH_OVFLW=61, p_RXBUF_THRESH_OVRD="FALSE", p_RXBUF_THRESH_UNDFLW=4, p_RXDLY_CFG=0x001F, p_RXDLY_LCFG=0x030, p_RXDLY_TAP_CFG=0x0000, p_RXPH_CFG=0x000000, p_RXPHDLY_CFG=0x084020, p_RXPH_MONITOR_SEL=0b00000, p_RX_XCLK_SEL="RXREC", p_RX_DDI_SEL=0b000000, p_RX_DEFER_RESET_BUF_EN="TRUE", # CDR Attributes p_RXCDR_CFG=0x03000023ff10100020, p_RXCDR_FR_RESET_ON_EIDLE=0b0, p_RXCDR_HOLD_DURING_EIDLE=0b0, p_RXCDR_PH_RESET_ON_EIDLE=0b0, p_RXCDR_LOCK_CFG=0b010101, # RX Initialization and Reset Attributes p_RXCDRFREQRESET_TIME=0b00001, p_RXCDRPHRESET_TIME=0b00001, p_RXISCANRESET_TIME=0b00001, p_RXPCSRESET_TIME=0b00001, p_RXPMARESET_TIME=0b00011, # RX OOB Signaling Attributes p_RXOOB_CFG=0b0000110, # RX Gearbox Attributes p_RXGEARBOX_EN="FALSE", p_GEARBOX_MODE=0b000, # PRBS Detection Attribute p_RXPRBS_ERR_LOOPBACK=0b0, # 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="TRUE", p_TXBUF_RESET_ON_RATE_CHANGE="TRUE", p_TXDLY_CFG=0x001F, p_TXDLY_LCFG=0x030, p_TXDLY_TAP_CFG=0x0000, p_TXPH_CFG=0x0780, p_TXPHDLY_CFG=0x084020, p_TXPH_MONITOR_SEL=0b00000, p_TX_XCLK_SEL="TXOUT", # FPGA TX Interface Attributes p_TX_DATA_WIDTH=20, # TX Configurable Driver Attributes p_TX_DEEMPH0=0b00000, p_TX_DEEMPH1=0b00000, p_TX_EIDLE_ASSERT_DELAY=0b110, p_TX_EIDLE_DEASSERT_DELAY=0b100, p_TX_LOOPBACK_DRIVE_HIZ="FALSE", p_TX_MAINCURSOR_SEL=0b0, 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=0b00001, p_TXPMARESET_TIME=0b00001, # TX Receiver Detection Attributes p_TX_RXDETECT_CFG=0x1832, p_TX_RXDETECT_REF=0b100, # CPLL Attributes p_CPLL_CFG=0xBC07DC, p_CPLL_FBDIV=pll.config["n2"], p_CPLL_FBDIV_45=pll.config["n1"], p_CPLL_INIT_CFG=0x00001E, p_CPLL_LOCK_CFG=0x01E8, p_CPLL_REFCLK_DIV=pll.config["m"], p_RXOUT_DIV=pll.config["d"], p_TXOUT_DIV=pll.config["d"], 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=0b0, p_RX_DFE_UT_CFG=0b10001111000000000, p_RX_DFE_VP_CFG=0b00011111100000011, # Power-Down Attributes p_RX_CLKMUX_PD=0b1, p_TX_CLKMUX_PD=0b1, # FPGA RX Interface Attribute p_RX_INT_DATAWIDTH=0, # FPGA TX Interface Attribute p_TX_INT_DATAWIDTH=0, # TX Configurable Driver Attributes p_TX_QPI_STATUS_EN=0b0, # RX Equalizer Attributes p_RX_DFE_KL_CFG2=0x301148AC, p_RX_DFE_XYD_CFG=0b0000000000000, # TX Configurable Driver Attributes p_TX_PREDRIVER_MODE=0b0) gtx_params.update( # CPLL Ports #o_CPLLFBCLKLOST =, o_CPLLLOCK=pll.lock, i_CPLLLOCKDETCLK=ClockSignal(), i_CPLLLOCKEN=1, i_CPLLPD=0, #o_CPLLREFCLKLOST =, i_CPLLREFCLKSEL=0b001, i_CPLLRESET=pll.reset, i_GTRSVD=0b0000000000000000, i_PCSRSVDIN=0b0000000000000000, i_PCSRSVDIN2=0b00000, i_PMARSVDIN=0b00000, i_PMARSVDIN2=0b00000, i_TSTIN=0b11111111111111111111, #o_TSTOUT =, # Channel i_CLKRSVD=0b0000, # Channel - Clocking Ports i_GTGREFCLK=0, i_GTNORTHREFCLK0=0, i_GTNORTHREFCLK1=0, i_GTREFCLK0=pll.refclk, i_GTREFCLK1=0, i_GTSOUTHREFCLK0=0, i_GTSOUTHREFCLK1=0, # Channel - DRP Ports i_DRPADDR=0, i_DRPCLK=0, i_DRPDI=0, #o_DRPDO =, i_DRPEN=0, #o_DRPRDY =, i_DRPWE=0, # Clocking Ports #o_GTREFCLKMONITOR =, i_QPLLCLK=0, i_QPLLREFCLK=0, i_RXSYSCLKSEL=0b00, i_TXSYSCLKSEL=0b00, # Digital Monitor Ports #o_DMONITOROUT =, # FPGA TX Interface Datapath Configuration i_TX8B10BEN=0, # Loopback Ports i_LOOPBACK=0b000, # PCI Express Ports #o_PHYSTATUS =, i_RXRATE=0b000, #o_RXVALID =, # Power-Down Ports i_RXPD=0b00, i_TXPD=0b00, # RX 8B/10B Decoder Ports i_SETERRSTATUS=0, # RX Initialization and Reset Ports i_EYESCANRESET=0, i_RXUSERRDY=rx_mmcm_locked, # RX Margin Analysis Ports #o_EYESCANDATAERROR =, i_EYESCANMODE=0, i_EYESCANTRIGGER=0, # Receive Ports - CDR Ports i_RXCDRFREQRESET=0, i_RXCDRHOLD=0, #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=0, # Receive Ports - FPGA RX Interface Ports i_RXUSRCLK=ClockSignal("eth_rx_half"), i_RXUSRCLK2=ClockSignal("eth_rx_half"), # Receive Ports - FPGA RX interface Ports o_RXDATA=Cat(*[rx_data[10 * i:10 * i + 8] for i in range(2)]), # Receive Ports - Pattern Checker Ports #o_RXPRBSERR =, i_RXPRBSSEL=0b000, # 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 i_RXDISPERR=Cat(*[rx_data[10 * i + 9] for i in range(2)]), #o_RXNOTINTABLE =, # Receive Ports - RX AFE i_GTXRXP=data_pads.rxp, # Receive Ports - RX AFE Ports i_GTXRXN=data_pads.rxn, # Receive Ports - RX Buffer Bypass Ports i_RXBUFRESET=0, #o_RXBUFSTATUS =, i_RXDDIEN=0, i_RXDLYBYPASS=1, i_RXDLYEN=0, i_RXDLYOVRDEN=0, i_RXDLYSRESET=0, #o_RXDLYSRESETDONE =, i_RXPHALIGN=0, #o_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=0b000, i_RXCHBONDMASTER=0, #o_RXCHBONDO =, i_RXCHBONDSLAVE=0, # Receive Ports - RX Channel Bonding Ports #o_RXCHANISALIGNED =, #o_RXCHANREALIGN =, # Receive Ports - RX Equailizer Ports i_RXLPMHFHOLD=0, i_RXLPMHFOVRDEN=0, i_RXLPMLFHOLD=0, # Receive Ports - RX Equalizer Ports i_RXDFEAGCHOLD=0, i_RXDFEAGCOVRDEN=0, i_RXDFECM1EN=0, i_RXDFELFHOLD=0, i_RXDFELFOVRDEN=1, 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=0, i_RXOSHOLD=0, i_RXOSOVRDEN=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=rx_reset, i_RXOOBRESET=0, i_RXPCSRESET=0, i_RXPMARESET=0, # Receive Ports - RX Margin Analysis ports i_RXLPMEN=0, # Receive Ports - RX OOB Signaling ports #o_RXCOMSASDET =, #o_RXCOMWAKEDET =, # Receive Ports - RX OOB Signaling ports #o_RXCOMINITDET =, # Receive Ports - RX OOB signalling Ports #o_RXELECIDLE =, i_RXELECIDLEMODE=0b11, # 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=Cat(*[rx_data[10 * i + 8] for i in range(2)]), # Receive Ports - Rx Channel Bonding Ports i_RXCHBONDI=0b00000, # Receive Ports -RX Initialization and Reset Ports o_RXRESETDONE=rx_reset_done, # Rx AFE Ports i_RXQPIEN=0, #o_RXQPISENN =, #o_RXQPISENP =, # TX Buffer Bypass Ports i_TXPHDLYTSTCLK=0, # TX Configurable Driver Ports i_TXPOSTCURSOR=0b00000, i_TXPOSTCURSORINV=0, i_TXPRECURSOR=0b00000, i_TXPRECURSORINV=0, i_TXQPIBIASEN=0, i_TXQPISTRONGPDOWN=0, i_TXQPIWEAKPUP=0, # TX Initialization and Reset Ports i_CFGRESET=0, i_GTTXRESET=tx_reset, #o_PCSRSVDOUT =, i_TXUSERRDY=tx_mmcm_locked, # Transceiver Reset Mode Operation i_GTRESETSEL=0, i_RESETOVRD=0, # Transmit Ports - 8b10b Encoder Control Ports i_TXCHARDISPMODE=Cat(*[tx_data[10 * i + 9] for i in range(2)]), i_TXCHARDISPVAL=Cat(*[tx_data[10 * i + 8] for i in range(2)]), # Transmit Ports - FPGA TX Interface Ports i_TXUSRCLK=ClockSignal("eth_tx_half"), i_TXUSRCLK2=ClockSignal("eth_tx_half"), # Transmit Ports - PCI Express Ports i_TXELECIDLE=0, i_TXMARGIN=0b000, i_TXRATE=0b000, i_TXSWING=0, # Transmit Ports - Pattern Generator Ports i_TXPRBSFORCEERR=0, # Transmit Ports - TX Buffer Bypass Ports i_TXDLYBYPASS=1, i_TXDLYEN=0, i_TXDLYHOLD=0, i_TXDLYOVRDEN=0, i_TXDLYSRESET=0, #o_TXDLYSRESETDONE =, i_TXDLYUPDOWN=0, i_TXPHALIGN=0, #o_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=0b0000000, i_TXPISOPD=0, # Transmit Ports - TX Data Path interface i_TXDATA=Cat(*[tx_data[10 * i:10 * i + 8] for i in range(2)]), # Transmit Ports - TX Driver and OOB signaling o_GTXTXN=data_pads.txn, o_GTXTXP=data_pads.txp, # Transmit Ports - TX Fabric Clock Output Control Ports o_TXOUTCLK=self.txoutclk, #o_TXOUTCLKFABRIC =, #o_TXOUTCLKPCS =, i_TXOUTCLKSEL=0b010, #o_TXRATEDONE =, # Transmit Ports - TX Gearbox Ports i_TXCHARISK=0b00000000, #o_TXGEARBOXREADY =, i_TXHEADER=0b000, i_TXSEQUENCE=0b0000000, i_TXSTARTSEQ=0, # Transmit Ports - TX Initialization and Reset Ports i_TXPCSRESET=0, i_TXPMARESET=0, o_TXRESETDONE=tx_reset_done, # Transmit Ports - TX OOB signaling Ports #o_TXCOMFINISH =, i_TXCOMINIT=0, i_TXCOMSAS=0, i_TXCOMWAKE=0, 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=0b00000000, # Transmit Ports - pattern Generator Ports i_TXPRBSSEL=0b000, # Tx Configurable Driver Ports #o_TXQPISENN =, #o_TXQPISENP =, ) self.specials += Instance("GTXE2_CHANNEL", **gtx_params) # Get 125MHz clocks back - the GTX is outputting 62.5MHz. txoutclk_rebuffer = Signal() self.specials += Instance("BUFH", i_I=self.txoutclk, o_O=txoutclk_rebuffer) rxoutclk_rebuffer = Signal() self.specials += Instance("BUFG", i_I=self.rxoutclk, o_O=rxoutclk_rebuffer) tx_mmcm_fb = Signal() tx_mmcm_reset = Signal(reset=1) clk_tx_unbuf = Signal() clk_tx_half_unbuf = Signal() self.specials += [ Instance( "MMCME2_BASE", p_CLKIN1_PERIOD=16.0, i_CLKIN1=txoutclk_rebuffer, i_RST=tx_mmcm_reset, o_CLKFBOUT=tx_mmcm_fb, i_CLKFBIN=tx_mmcm_fb, p_CLKFBOUT_MULT_F=16, o_LOCKED=tx_mmcm_locked, p_DIVCLK_DIVIDE=1, p_CLKOUT0_DIVIDE_F=16, o_CLKOUT0=clk_tx_half_unbuf, p_CLKOUT1_DIVIDE=8, o_CLKOUT1=clk_tx_unbuf, ), Instance("BUFH", i_I=clk_tx_half_unbuf, o_O=self.cd_eth_tx_half.clk), Instance("BUFH", i_I=clk_tx_unbuf, o_O=self.cd_eth_tx.clk), AsyncResetSynchronizer(self.cd_eth_tx, ~tx_mmcm_locked) ] rx_mmcm_fb = Signal() rx_mmcm_reset = Signal(reset=1) clk_rx_unbuf = Signal() clk_rx_half_unbuf = Signal() self.specials += [ Instance( "MMCME2_BASE", p_CLKIN1_PERIOD=16.0, i_CLKIN1=rxoutclk_rebuffer, i_RST=rx_mmcm_reset, o_CLKFBOUT=rx_mmcm_fb, i_CLKFBIN=rx_mmcm_fb, p_CLKFBOUT_MULT_F=16, o_LOCKED=rx_mmcm_locked, p_DIVCLK_DIVIDE=1, p_CLKOUT0_DIVIDE_F=16, o_CLKOUT0=clk_rx_half_unbuf, p_CLKOUT1_DIVIDE=8, o_CLKOUT1=clk_rx_unbuf, ), Instance("BUFG", i_I=clk_rx_half_unbuf, o_O=self.cd_eth_rx_half.clk), Instance("BUFG", i_I=clk_rx_unbuf, o_O=self.cd_eth_rx.clk), AsyncResetSynchronizer(self.cd_eth_rx, ~rx_mmcm_locked) ] # Transceiver init tx_init = GTXTXInit(sys_clk_freq, buffer_enable=True) self.comb += [ pll.reset.eq(tx_init.pllreset), tx_init.plllock.eq(pll.lock), tx_reset.eq(tx_init.gtXxreset) ] self.sync += tx_mmcm_reset.eq(~pll.lock) tx_mmcm_reset.attr.add("no_retiming") rx_init = ResetInserter()(GTXRXInit(sys_clk_freq, buffer_enable=True)) self.submodules += rx_init self.comb += [ rx_init.reset.eq(~tx_init.done), rx_reset.eq(rx_init.gtXxreset) ] ps_restart = PulseSynchronizer("eth_tx", "sys") self.submodules += ps_restart self.comb += [ ps_restart.i.eq(pcs.restart), rx_init.restart.eq(ps_restart.o) ] # Unlike CDRs from serious vendors, Xilinx CDRs can't tell you # when they are locked. Assume CDR lock time is 50,000 UI, # as per DS183. The Xilinx "wizards" also assume that. cdr_lock_time = round(sys_clk_freq * 50e3 / 1.25e9) cdr_lock_counter = Signal(max=cdr_lock_time + 1) cdr_locked = Signal() self.sync += [ If(rx_reset, cdr_locked.eq(0), cdr_lock_counter.eq(0)).Elif( cdr_lock_counter != cdr_lock_time, cdr_lock_counter.eq(cdr_lock_counter + 1)).Else( cdr_locked.eq(1)), rx_mmcm_reset.eq(~cdr_locked) ] rx_mmcm_reset.attr.add("no_retiming") # Gearbox and PCS connection gearbox = Gearbox() self.submodules += gearbox self.comb += [ tx_data.eq(gearbox.tx_data_half), gearbox.rx_data_half.eq(rx_data), gearbox.tx_data.eq(pcs.tbi_tx), pcs.tbi_rx.eq(gearbox.rx_data) ]
def __init__(self, link_layer, min_mem_dw): ll_dw = len(link_layer.tx_aux_data) mem_dw = max(min_mem_dw, ll_dw) self.aux_tx_length = CSRStorage(bits_for(max_packet), alignment_bits=log2_int(mem_dw//8)) self.aux_tx = CSR() self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) converter = ClockDomainsRenamer("rtio")( stream.Converter(mem_dw, ll_dw)) self.submodules += converter # when continuously fed, the Converter outputs data continuously self.comb += [ converter.source.ack.eq(link_layer.tx_aux_ack), link_layer.tx_aux_frame.eq(converter.source.stb), link_layer.tx_aux_data.eq(converter.source.data) ] seen_eop_rst = Signal() frame_r = Signal() seen_eop = Signal() self.sync.rtio += [ If(link_layer.tx_aux_ack, frame_r.eq(link_layer.tx_aux_frame), If(frame_r & ~link_layer.tx_aux_frame, seen_eop.eq(1)) ), If(seen_eop_rst, seen_eop.eq(0)) ] mem_port = self.mem.get_port(clock_domain="rtio") self.specials += mem_port self.aux_tx_length.storage.attr.add("no_retiming") tx_length = Signal(bits_for(max_packet)) self.specials += MultiReg(self.aux_tx_length.storage, tx_length, "rtio") frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) frame_counter_next = Signal(frame_counter_nbits) frame_counter_ce = Signal() frame_counter_rst = Signal() self.comb += [ frame_counter_next.eq(frame_counter), If(frame_counter_rst, frame_counter_next.eq(0) ).Elif(frame_counter_ce, frame_counter_next.eq(frame_counter + 1) ), mem_port.adr.eq(frame_counter_next), converter.sink.data.eq(mem_port.dat_r) ] self.sync.rtio += frame_counter.eq(frame_counter_next) start_tx = PulseSynchronizer("sys", "rtio") tx_done = PulseSynchronizer("rtio", "sys") self.submodules += start_tx, tx_done self.comb += start_tx.i.eq(self.aux_tx.re) self.sync += [ If(tx_done.o, self.aux_tx.w.eq(0)), If(self.aux_tx.re, self.aux_tx.w.eq(1)) ] fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += fsm fsm.act("IDLE", frame_counter_rst.eq(1), seen_eop_rst.eq(1), If(start_tx.o, NextState("TRANSMIT")) ) fsm.act("TRANSMIT", converter.sink.stb.eq(1), If(converter.sink.ack, frame_counter_ce.eq(1) ), If(frame_counter_next == tx_length, NextState("WAIT_INTERFRAME")) ) fsm.act("WAIT_INTERFRAME", If(seen_eop, tx_done.i.eq(1), NextState("IDLE") ) )
def __init__(self, link_layer, min_mem_dw): self.aux_rx_length = CSRStatus(bits_for(max_packet)) self.aux_rx_present = CSR() self.aux_rx_error = CSR() ll_dw = len(link_layer.rx_aux_data) mem_dw = max(min_mem_dw, ll_dw) self.specials.mem = Memory(mem_dw, max_packet//(mem_dw//8)) converter = ClockDomainsRenamer("rtio_rx")( stream.Converter(ll_dw, mem_dw)) self.submodules += converter # when continuously drained, the Converter accepts data continuously frame_r = Signal() self.sync.rtio_rx += [ If(link_layer.rx_aux_stb, frame_r.eq(link_layer.rx_aux_frame), converter.sink.data.eq(link_layer.rx_aux_data) ) ] self.comb += [ converter.sink.stb.eq(link_layer.rx_aux_stb & frame_r), converter.sink.eop.eq(converter.sink.stb & ~link_layer.rx_aux_frame) ] mem_port = self.mem.get_port(write_capable=True, clock_domain="rtio_rx") self.specials += mem_port frame_counter_nbits = bits_for(max_packet) - log2_int(mem_dw//8) frame_counter = Signal(frame_counter_nbits) self.comb += [ mem_port.adr.eq(frame_counter), mem_port.dat_w.eq(converter.source.data), converter.source.ack.eq(1) ] frame_counter.attr.add("no_retiming") frame_counter_sys = Signal(frame_counter_nbits) self.specials += MultiReg(frame_counter, frame_counter_sys) self.comb += self.aux_rx_length.status.eq(frame_counter_sys << log2_int(mem_dw//8)) signal_frame = PulseSynchronizer("rtio_rx", "sys") frame_ack = PulseSynchronizer("sys", "rtio_rx") signal_error = PulseSynchronizer("rtio_rx", "sys") self.submodules += signal_frame, frame_ack, signal_error self.sync += [ If(self.aux_rx_present.re, self.aux_rx_present.w.eq(0)), If(signal_frame.o, self.aux_rx_present.w.eq(1)), If(self.aux_rx_error.re, self.aux_rx_error.w.eq(0)), If(signal_error.o, self.aux_rx_error.w.eq(1)) ] self.comb += frame_ack.i.eq(self.aux_rx_present.re) fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="IDLE")) self.submodules += fsm sop = Signal(reset=1) self.sync.rtio_rx += \ If(converter.source.stb, If(converter.source.eop, sop.eq(1) ).Else( sop.eq(0) ) ) fsm.act("IDLE", If(converter.source.stb & sop, NextValue(frame_counter, frame_counter + 1), mem_port.we.eq(1), If(converter.source.eop, NextState("SIGNAL_FRAME") ).Else( NextState("FRAME") ) ).Else( NextValue(frame_counter, 0) ) ) fsm.act("FRAME", If(converter.source.stb, NextValue(frame_counter, frame_counter + 1), mem_port.we.eq(1), If(frame_counter == max_packet, mem_port.we.eq(0), signal_error.i.eq(1), NextState("IDLE") # discard the rest of the frame ), If(converter.source.eop, NextState("SIGNAL_FRAME") ) ) ) fsm.act("SIGNAL_FRAME", signal_frame.i.eq(1), NextState("WAIT_ACK"), If(converter.source.stb, signal_error.i.eq(1)) ) fsm.act("WAIT_ACK", If(frame_ack.o, NextValue(frame_counter, 0), NextState("IDLE") ), If(converter.source.stb, signal_error.i.eq(1)) )
def __init__(self, lsb_first=False, check_period=6e-3, more_ack_time=10e-3): self.submodules.tx = ClockDomainsRenamer("eth_tx")( TransmitPath(lsb_first=lsb_first)) self.submodules.rx = ClockDomainsRenamer("eth_rx")( ReceivePath(lsb_first=lsb_first)) self.tbi_tx = self.tx.encoder.output[0] self.tbi_rx = self.rx.decoder.input self.sink = stream.Endpoint(eth_phy_description(8)) self.source = stream.Endpoint(eth_phy_description(8)) self.link_up = Signal() self.restart = Signal() # # # # endpoint interface self.comb += [ self.tx.tx_stb.eq(self.sink.valid), self.sink.ready.eq(self.tx.tx_ack), self.tx.tx_data.eq(self.sink.data), ] rx_en_d = Signal() self.sync.eth_rx += [ rx_en_d.eq(self.rx.rx_en), self.source.valid.eq(self.rx.rx_en), self.source.data.eq(self.rx.rx_data) ] self.comb += self.source.last.eq(~self.rx.rx_en & rx_en_d) # main module seen_valid_ci = PulseSynchronizer("eth_rx", "eth_tx") self.submodules += seen_valid_ci self.comb += seen_valid_ci.i.eq(self.rx.seen_valid_ci) checker_max_val = ceil(check_period*125e6) checker_counter = Signal(max=checker_max_val+1) checker_tick = Signal() checker_ok = Signal() self.sync.eth_tx += [ checker_tick.eq(0), If(checker_counter == 0, checker_tick.eq(1), checker_counter.eq(checker_max_val) ).Else( checker_counter.eq(checker_counter-1) ), If(seen_valid_ci.o, checker_ok.eq(1)), If(checker_tick, checker_ok.eq(0)) ] autoneg_ack = Signal() self.comb += self.tx.config_reg.eq((1 << 5) | (autoneg_ack << 14)) rx_config_reg = PulseSynchronizer("eth_rx", "eth_tx") rx_config_reg_ack = PulseSynchronizer("eth_rx", "eth_tx") self.submodules += rx_config_reg, rx_config_reg_ack more_ack_timer = ClockDomainsRenamer("eth_tx")( WaitTimer(ceil(more_ack_time*125e6))) self.submodules += more_ack_timer fsm = ClockDomainsRenamer("eth_tx")(FSM()) self.submodules += fsm fsm.act("AUTONEG_WAIT_CONFIG_REG", self.tx.config_stb.eq(1), If(rx_config_reg.o|rx_config_reg_ack.o, NextState("AUTONEG_WAIT_ACK") ), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_CONFIG_REG") ) ) fsm.act("AUTONEG_WAIT_ACK", self.tx.config_stb.eq(1), autoneg_ack.eq(1), If(rx_config_reg_ack.o, NextState("AUTONEG_SEND_MORE_ACK") ), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_CONFIG_REG") ) ) fsm.act("AUTONEG_SEND_MORE_ACK", self.tx.config_stb.eq(1), autoneg_ack.eq(1), more_ack_timer.wait.eq(1), If(more_ack_timer.done, NextState("RUNNING") ), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_CONFIG_REG") ) ) fsm.act("RUNNING", self.link_up.eq(1), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_CONFIG_REG") ) ) c_counter = Signal(max=5) previous_config_reg = Signal(16) self.sync.eth_rx += [ If(self.rx.seen_config_reg, c_counter.eq(4) ).Elif(c_counter != 0, c_counter.eq(c_counter - 1) ), rx_config_reg_ack.i.eq(0), rx_config_reg.i.eq(0), If(self.rx.seen_config_reg, previous_config_reg.eq(self.rx.config_reg), # two identical config_reg in immediate succession If((c_counter == 1) & (previous_config_reg == self.rx.config_reg), If(previous_config_reg[14], rx_config_reg_ack.i.eq(1) ).Else( rx_config_reg.i.eq(1) ) ) ) ]
def __init__(self, lsb_first=False, check_period=6e-3, more_ack_time=10e-3): self.submodules.tx = ClockDomainsRenamer("eth_tx")( TransmitPath(lsb_first=lsb_first)) self.submodules.rx = ClockDomainsRenamer("eth_rx")( ReceivePath(lsb_first=lsb_first)) self.tbi_tx = self.tx.encoder.output[0] self.tbi_rx = self.rx.decoder.input self.sink = stream.Endpoint(eth_phy_layout(8)) self.source = stream.Endpoint(eth_phy_layout(8)) self.link_up = Signal() self.restart = Signal() self.lp_abi = BusSynchronizer(16, "eth_rx", "eth_tx") self.submodules += self.lp_abi # # # # endpoint interface self.comb += [ self.tx.tx_stb.eq(self.sink.stb), self.sink.ack.eq(self.tx.tx_ack), self.tx.tx_data.eq(self.sink.data), ] rx_en_d = Signal() self.sync.eth_rx += [ rx_en_d.eq(self.rx.rx_en), self.source.stb.eq(self.rx.sample_en), self.source.data.eq(self.rx.rx_data) ] self.comb += self.source.eop.eq(~self.rx.rx_en & rx_en_d) # main module seen_valid_ci = PulseSynchronizer("eth_rx", "eth_tx") self.submodules += seen_valid_ci self.comb += seen_valid_ci.i.eq(self.rx.seen_valid_ci) checker_max_val = ceil(check_period * 125e6) checker_counter = Signal(max=checker_max_val + 1) checker_tick = Signal() checker_ok = Signal() self.sync.eth_tx += [ checker_tick.eq(0), If(checker_counter == 0, checker_tick.eq(1), checker_counter.eq(checker_max_val)).Else( checker_counter.eq(checker_counter - 1)), If(seen_valid_ci.o, checker_ok.eq(1)), If(checker_tick, checker_ok.eq(0)) ] # Control if tx_config_reg should be empty tx_config_empty = Signal() # Detections in SGMII mode is_sgmii = Signal() linkdown = Signal() self.comb += [ is_sgmii.eq(self.lp_abi.o[0]), # Detect that link is down: # - 1000BASE-X: linkup can be inferred by non-empty reg # - SGMII: linkup is indicated with bit 15 linkdown.eq((self.lp_abi.o[0] & ~self.lp_abi.o[15]) | (self.lp_abi.o == 0)), self.tx.sgmii_speed.eq( Mux(self.lp_abi.o[0], self.lp_abi.o[10:12], 0b10)), self.rx.sgmii_speed.eq( Mux(self.lp_abi.i[0], self.lp_abi.i[10:12], 0b10)) ] autoneg_ack = Signal() self.comb += [ self.tx.config_reg.eq( Mux( tx_config_empty, 0, (is_sgmii) | # SGMII: SGMII in-use (~is_sgmii << 5) | # 1000BASE-X: Full-duplex ( Mux( self.lp_abi.o[0], # SGMII: Speed self.lp_abi.o[10:12], 0) << 10) | (is_sgmii << 12) | # SGMII: Full-duplex (autoneg_ack << 14) | # SGMII/1000BASE-X: Acknowledge Bit (is_sgmii & self.link_up) # SGMII: Link-up )) ] rx_config_reg_abi = PulseSynchronizer("eth_rx", "eth_tx") rx_config_reg_ack = PulseSynchronizer("eth_rx", "eth_tx") self.submodules += [rx_config_reg_abi, rx_config_reg_ack] more_ack_timer = ClockDomainsRenamer("eth_tx")(WaitTimer( ceil(more_ack_time * 125e6))) # SGMII: use 1.6ms link_timer sgmii_ack_timer = ClockDomainsRenamer("eth_tx")(WaitTimer( ceil(1.6e-3 * 125e6))) self.submodules += more_ack_timer, sgmii_ack_timer fsm = ClockDomainsRenamer("eth_tx")(FSM()) self.submodules += fsm # AN_ENABLE fsm.act("AUTONEG_BREAKLINK", self.tx.config_stb.eq(1), tx_config_empty.eq(1), more_ack_timer.wait.eq(1), If(more_ack_timer.done, NextState("AUTONEG_WAIT_ABI"))) # ABILITY_DETECT fsm.act( "AUTONEG_WAIT_ABI", self.tx.config_stb.eq(1), If(rx_config_reg_abi.o, NextState("AUTONEG_WAIT_ACK")), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_BREAKLINK"))) # ACKNOWLEDGE_DETECT fsm.act( "AUTONEG_WAIT_ACK", self.tx.config_stb.eq(1), autoneg_ack.eq(1), If(rx_config_reg_ack.o, NextState("AUTONEG_SEND_MORE_ACK")), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_BREAKLINK"))) # COMPLETE_ACKNOWLEDGE fsm.act( "AUTONEG_SEND_MORE_ACK", self.tx.config_stb.eq(1), autoneg_ack.eq(1), more_ack_timer.wait.eq(~is_sgmii), sgmii_ack_timer.wait.eq(is_sgmii), If((is_sgmii & sgmii_ack_timer.done) | (~is_sgmii & more_ack_timer.done), NextState("RUNNING")), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_BREAKLINK"))) # LINK_OK fsm.act( "RUNNING", self.link_up.eq(1), If((checker_tick & ~checker_ok) | linkdown, self.restart.eq(1), NextState("AUTONEG_BREAKLINK"))) c_counter = Signal(max=5) prev_config_reg = Signal(16) self.sync.eth_rx += [ # Restart consistency counter If(self.rx.seen_config_reg, c_counter.eq(4)).Elif(c_counter != 0, c_counter.eq(c_counter - 1)), rx_config_reg_abi.i.eq(0), rx_config_reg_ack.i.eq(0), If( self.rx.seen_config_reg, # Record current config_reg for comparison in the next clock cycle prev_config_reg.eq(self.rx.config_reg), # Compare consecutive values of config_reg If( (c_counter == 1) & (prev_config_reg & 0xbfff == self.rx.config_reg & 0xbfff), # Acknowledgement/Consistency match If( prev_config_reg[14] & self.rx.config_reg[14], rx_config_reg_ack.i.eq(1), ) # Ability match .Else(rx_config_reg_abi.i.eq(1), )), # Record advertised ability of link partner self.lp_abi.i.eq(self.rx.config_reg)) ]
def __init__(self, lsb_first=False, check_period=6e-3, more_ack_time=10e-3): self.submodules.tx = ClockDomainsRenamer("eth_tx")( TransmitPath(lsb_first=lsb_first)) self.submodules.rx = ClockDomainsRenamer("eth_rx")( ReceivePath(lsb_first=lsb_first)) self.tbi_tx = self.tx.encoder.output[0] self.tbi_rx = self.rx.decoder.input self.sink = stream.Endpoint(eth_phy_description(8)) self.source = stream.Endpoint(eth_phy_description(8)) self.link_up = Signal() self.restart = Signal() # SGMII Speed Adaptation is_sgmii = Signal() self.link_partner_adv_ability = Signal(16) # # # # endpoint interface self.comb += [ self.tx.tx_stb.eq(self.sink.valid), self.sink.ready.eq(self.tx.tx_ack), self.tx.tx_data.eq(self.sink.data), ] rx_en_d = Signal() self.sync.eth_rx += [ rx_en_d.eq(self.rx.rx_en), self.source.valid.eq(self.rx.sample_en), self.source.data.eq(self.rx.rx_data) ] self.comb += self.source.last.eq(~self.rx.rx_en & rx_en_d) # main module seen_valid_ci = PulseSynchronizer("eth_rx", "eth_tx") self.submodules += seen_valid_ci self.comb += seen_valid_ci.i.eq(self.rx.seen_valid_ci) checker_max_val = ceil(check_period * 125e6) checker_counter = Signal(max=checker_max_val + 1) checker_tick = Signal() checker_ok = Signal() self.sync.eth_tx += [ checker_tick.eq(0), If(checker_counter == 0, checker_tick.eq(1), checker_counter.eq(checker_max_val)).Else( checker_counter.eq(checker_counter - 1)), If(seen_valid_ci.o, checker_ok.eq(1)), If(checker_tick, checker_ok.eq(0)) ] autoneg_ack = Signal() self.comb += self.tx.config_reg.eq((is_sgmii) | # SGMII-specific (~is_sgmii << 5) | # Full-duplex (autoneg_ack << 14) # ACK ) rx_config_reg_abi = PulseSynchronizer("eth_rx", "eth_tx") rx_config_reg_ack = PulseSynchronizer("eth_rx", "eth_tx") self.submodules += [rx_config_reg_abi, rx_config_reg_ack] more_ack_timer = ClockDomainsRenamer("eth_tx")(WaitTimer( ceil(more_ack_time * 125e6))) self.submodules += more_ack_timer fsm_inited = Signal() config_reg_empty = Signal() fsm = ClockDomainsRenamer("eth_tx")(FSM()) self.submodules += fsm fsm.act( "AUTONEG_WAIT_ABI", self.tx.config_stb.eq(fsm_inited), If(rx_config_reg_abi.o, NextValue(fsm_inited, 1), NextState("AUTONEG_WAIT_ACK")), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_ABI"))) fsm.act( "AUTONEG_WAIT_ACK", self.tx.config_stb.eq(1), autoneg_ack.eq(1), If(rx_config_reg_ack.o, NextState("AUTONEG_SEND_MORE_ACK")), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_ABI"))) # COMPLETE_ACKNOWLEDGE fsm.act( "AUTONEG_SEND_MORE_ACK", self.tx.config_stb.eq(1), autoneg_ack.eq(1), more_ack_timer.wait.eq(1), If(more_ack_timer.done, NextState("RUNNING")), If(checker_tick & ~checker_ok, self.restart.eq(1), NextState("AUTONEG_WAIT_ABI"))) # LINK_OK fsm.act( "RUNNING", self.link_up.eq(1), If((checker_tick & ~checker_ok) | config_reg_empty, self.restart.eq(1), NextState("AUTONEG_WAIT_ABI"))) c_counter = Signal(max=5) previous_config_reg = Signal(16) preack_config_reg = Signal(16) self.sync.eth_rx += [ # Restart consistency counter If(self.rx.seen_config_reg, c_counter.eq(4)).Elif(c_counter != 0, c_counter.eq(c_counter - 1)), rx_config_reg_abi.i.eq(0), rx_config_reg_ack.i.eq(0), If( self.rx.seen_config_reg, previous_config_reg.eq(self.rx.config_reg), If( (c_counter == 1) & ((previous_config_reg | 0x4000) == (self.rx.config_reg | 0x4000)) & ((self.rx.config_reg | 1) != 1), # Ability match rx_config_reg_abi.i.eq(1), preack_config_reg.eq(previous_config_reg), # Acknowledgement/Consistency match If((previous_config_reg[14] & self.rx.config_reg[14]) & ((preack_config_reg | 0x4000) == (self.rx.config_reg | 0x4000)), rx_config_reg_ack.i.eq(1))), # Record advertised ability of link partner self.link_partner_adv_ability.eq(self.rx.config_reg)) ] # Speed detection via SGMII sgmii_speed = Mux(is_sgmii, self.link_partner_adv_ability[10:12], 0b10) self.comb += [ is_sgmii.eq(self.link_partner_adv_ability[0]), self.tx.sgmii_speed.eq(sgmii_speed), self.rx.sgmii_speed.eq(sgmii_speed) ] # Detect that config_reg is empty self.comb += [ config_reg_empty.eq((self.link_partner_adv_ability | 1) == 1) ]
def __init__(self, pads): self.gpio_enable = CSRStorage(reset=1) self.gpio_in = CSRStatus(2) self.gpio_out = CSRStorage(2) self.gpio_oe = CSRStorage(2) self.i2c_divider = CSRStorage(16) self.i2c_address = CSRStorage(7) self.errors = CSR(2) # in helper clock domain self.adpll = Signal(24) self.adpll_stb = Signal() # # # programmer = ClockDomainsRenamer("helper")(ADPLLProgrammer()) self.submodules += programmer self.i2c_divider.storage.attr.add("no_retiming") self.i2c_address.storage.attr.add("no_retiming") self.specials += [ MultiReg(self.i2c_divider.storage, programmer.i2c_divider, "helper"), MultiReg(self.i2c_address.storage, programmer.i2c_address, "helper") ] self.comb += [ programmer.adpll.eq(self.adpll), programmer.adpll_stb.eq(self.adpll_stb) ] self.gpio_enable.storage.attr.add("no_retiming") self.gpio_out.storage.attr.add("no_retiming") self.gpio_oe.storage.attr.add("no_retiming") # SCL GPIO and mux ts_scl = TSTriple(1) self.specials += ts_scl.get_tristate(pads.scl) status = Signal() self.comb += self.gpio_in.status[0].eq(status) self.specials += MultiReg(ts_scl.i, status) self.comb += [ If(self.gpio_enable.storage, ts_scl.o.eq(self.gpio_out.storage[0]), ts_scl.oe.eq(self.gpio_oe.storage[0])).Else( ts_scl.o.eq(programmer.scl), ts_scl.oe.eq(1)) ] # SDA GPIO and mux ts_sda = TSTriple(1) self.specials += ts_sda.get_tristate(pads.sda) status = Signal() self.comb += self.gpio_in.status[1].eq(status) self.specials += MultiReg(ts_sda.i, status) self.comb += [ If(self.gpio_enable.storage, ts_sda.o.eq(self.gpio_out.storage[1]), ts_sda.oe.eq(self.gpio_oe.storage[1])).Else( ts_sda.o.eq(0), ts_sda.oe.eq(~programmer.sda_o)) ] self.specials += MultiReg(ts_sda.i, programmer.sda_i, "helper") # Error reporting collision_cdc = BlindTransfer("helper", "sys") self.submodules += collision_cdc self.comb += collision_cdc.i.eq(programmer.stb & programmer.busy) nack_cdc = PulseSynchronizer("helper", "sys") self.submodules += nack_cdc self.comb += nack_cdc.i.eq(programmer.nack) for n, trig in enumerate([collision_cdc.o, nack_cdc.o]): self.sync += [ If(self.errors.re & self.errors.r[n], self.errors.w[n].eq(0)), If(trig, self.errors.w[n].eq(1)) ]