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, dram_port, random=True): self.reset = CSR() self.start = CSR() self.base = CSRStorage(dram_port.aw) self.length = CSRStorage(dram_port.aw) self.done = CSRStatus() self.err_count = CSRStatus(32) # # # cd = dram_port.cd core = _LiteDRAMBISTChecker(dram_port, random) self.submodules.core = ClockDomainsRenamer(cd)(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(dram_port.aw, "sys", cd) length_sync = BusSynchronizer(dram_port.aw, "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), ] err_count_sync = BusSynchronizer(32, cd, "sys") self.submodules += err_count_sync self.comb += [ err_count_sync.i.eq(core.err_count), self.err_count.status.eq(err_count_sync.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) # 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( reduce(add, [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( reduce(or_, [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, 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 __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, 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, 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, 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, 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, phy, dw, endianness="big", with_preamble_crc=True, with_padding=True): if dw < phy.dw: raise ValueError("Core data width({}) must be larger than PHY data width({})".format(dw, phy.dw)) rx_pipeline = [phy] tx_pipeline = [phy] # Interpacket gap tx_gap_inserter = gap.LiteEthMACGap(phy.dw) rx_gap_checker = gap.LiteEthMACGap(phy.dw, ack_on_gap=True) self.submodules += ClockDomainsRenamer("eth_tx")(tx_gap_inserter) self.submodules += ClockDomainsRenamer("eth_rx")(rx_gap_checker) tx_pipeline += [tx_gap_inserter] rx_pipeline += [rx_gap_checker] # Preamble / CRC if isinstance(phy, LiteEthPHYModel): # In simulation, avoid CRC/Preamble to enable direct connection # to the Ethernet tap. self._preamble_crc = CSRStatus(reset=1) elif with_preamble_crc: self._preamble_crc = CSRStatus(reset=1) self.crc_errors = CSRStatus(32) # Preamble insert/check preamble_inserter = preamble.LiteEthMACPreambleInserter(phy.dw) preamble_checker = preamble.LiteEthMACPreambleChecker(phy.dw) self.submodules += ClockDomainsRenamer("eth_tx")(preamble_inserter) self.submodules += ClockDomainsRenamer("eth_rx")(preamble_checker) # CRC insert/check crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_phy_description(phy.dw)) crc32_checker = crc.LiteEthMACCRC32Checker(eth_phy_description(phy.dw)) self.submodules += ClockDomainsRenamer("eth_tx")(crc32_inserter) self.submodules += ClockDomainsRenamer("eth_rx")(crc32_checker) tx_pipeline += [preamble_inserter, crc32_inserter] rx_pipeline += [preamble_checker, crc32_checker] # CRC error counter self.submodules.ps_crc_error = PulseSynchronizer("eth_rx", "sys") self.comb += self.ps_crc_error.i.eq(crc32_checker.crc_error) self.sync += [ If(self.ps_crc_error.o, self.crc_errors.status.eq(self.crc_errors.status + 1))] # Padding if with_padding: padding_inserter = padding.LiteEthMACPaddingInserter(phy.dw, 60) padding_checker = padding.LiteEthMACPaddingChecker(phy.dw, 60) self.submodules += ClockDomainsRenamer("eth_tx")(padding_inserter) self.submodules += ClockDomainsRenamer("eth_rx")(padding_checker) tx_pipeline += [padding_inserter] rx_pipeline += [padding_checker] # Delimiters if dw != 8: tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw) rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw) self.submodules += ClockDomainsRenamer("eth_tx")(tx_last_be) self.submodules += ClockDomainsRenamer("eth_rx")(rx_last_be) tx_pipeline += [tx_last_be] rx_pipeline += [rx_last_be] # Converters if dw != phy.dw: reverse = endianness == "big" tx_converter = stream.StrideConverter(eth_phy_description(dw), eth_phy_description(phy.dw), reverse=reverse) rx_converter = stream.StrideConverter(eth_phy_description(phy.dw), eth_phy_description(dw), reverse=reverse) self.submodules += ClockDomainsRenamer("eth_tx")(tx_converter) self.submodules += ClockDomainsRenamer("eth_rx")(rx_converter) tx_pipeline += [tx_converter] rx_pipeline += [rx_converter] # Cross Domain Crossing tx_cdc = stream.AsyncFIFO(eth_phy_description(dw), 64) rx_cdc = stream.AsyncFIFO(eth_phy_description(dw), 64) self.submodules += ClockDomainsRenamer({"write": "sys", "read": "eth_tx"})(tx_cdc) self.submodules += ClockDomainsRenamer({"write": "eth_rx", "read": "sys"})(rx_cdc) tx_pipeline += [tx_cdc] rx_pipeline += [rx_cdc] # Graph self.submodules.tx_pipeline = stream.Pipeline(*reversed(tx_pipeline)) self.submodules.rx_pipeline = stream.Pipeline(*rx_pipeline) self.sink, self.source = self.tx_pipeline.sink, self.rx_pipeline.source
def __init__(self, i, idomain, o, odomain): PulseSynchronizer.__init__(self, idomain, odomain) self.comb += [ self.i.eq(i), o.eq(self.o) ]
def __init__(self, pad_p, pad_n, ntbits=8): self.serdesstrobe = Signal() self.d = Signal(10) self._dly_ctl = CSR(6) self._dly_busy = CSRStatus(2) self._phase = CSRStatus(2) self._phase_reset = CSR() # # # # IO pad_se = Signal() self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se) pad_delayed_master = Signal() pad_delayed_slave = Signal() delay_inc = Signal() delay_ce = Signal() delay_master_cal = Signal() delay_master_rst = Signal() delay_master_busy = Signal() delay_slave_cal = Signal() delay_slave_rst = Signal() delay_slave_busy = Signal() self.specials += [ Instance("IODELAY2", p_SERDES_MODE="MASTER", p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR", i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master, i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"), i_INC=delay_inc, i_CE=delay_ce, i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy, i_T=1), Instance("IODELAY2", p_SERDES_MODE="SLAVE", p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR", p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR", i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave, i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"), i_INC=delay_inc, i_CE=delay_ce, i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy, i_T=1) ] dsr2 = Signal(5) pd_valid = Signal() pd_incdec = Signal() pd_edge = Signal() pd_cascade = Signal() self.specials += [ Instance("ISERDES2", p_SERDES_MODE="MASTER", p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5, p_INTERFACE_TYPE="RETIMED", i_D=pad_delayed_master, o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1], i_BITSLIP=0, i_CE0=1, i_RST=0, i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"), i_IOCE=self.serdesstrobe, o_VALID=pd_valid, o_INCDEC=pd_incdec, i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade), Instance("ISERDES2", p_SERDES_MODE="SLAVE", p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5, p_INTERFACE_TYPE="RETIMED", i_D=pad_delayed_slave, o_Q4=dsr2[0], i_BITSLIP=0, i_CE0=1, i_RST=0, i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"), i_IOCE=self.serdesstrobe, i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge) ] # Phase error accumulator lateness = Signal(ntbits, reset=2**(ntbits - 1)) too_late = Signal() too_early = Signal() reset_lateness = Signal() self.comb += [ too_late.eq(lateness == (2**ntbits - 1)), too_early.eq(lateness == 0) ] self.sync.pix2x += [ If(reset_lateness, lateness.eq(2**(ntbits - 1))).Elif( ~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early, If(pd_valid & pd_incdec, lateness.eq(lateness - 1)), If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1))) ] # Delay control self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys") delay_master_pending = Signal() self.sync.pix2x += [ self.delay_master_done.i.eq(0), If(~delay_master_pending, If(delay_master_cal | delay_ce, delay_master_pending.eq(1))).Else( If(~delay_master_busy, self.delay_master_done.i.eq(1), delay_master_pending.eq(0))) ] self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys") delay_slave_pending = Signal() self.sync.pix2x += [ self.delay_slave_done.i.eq(0), If(~delay_slave_pending, If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1))).Else( If(~delay_slave_busy, self.delay_slave_done.i.eq(1), delay_slave_pending.eq(0))) ] self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x") self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x") self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x") self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x") self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x") self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x") self.comb += [ delay_master_cal.eq(self.do_delay_master_cal.o), delay_master_rst.eq(self.do_delay_master_rst.o), delay_slave_cal.eq(self.do_delay_slave_cal.o), delay_slave_rst.eq(self.do_delay_slave_rst.o), delay_inc.eq(self.do_delay_inc.o), delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o), ] sys_delay_master_pending = Signal() self.sync += [ If( self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i, sys_delay_master_pending.eq(1)).Elif( self.delay_master_done.o, sys_delay_master_pending.eq(0)) ] sys_delay_slave_pending = Signal() self.sync += [ If( self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i, sys_delay_slave_pending.eq(1)).Elif( self.delay_slave_done.o, sys_delay_slave_pending.eq(0)) ] self.comb += [ self.do_delay_master_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]), self.do_delay_master_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[1]), self.do_delay_slave_cal.i.eq(self._dly_ctl.re & self._dly_ctl.r[2]), self.do_delay_slave_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[3]), self.do_delay_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[4]), self.do_delay_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[5]), self._dly_busy.status.eq( Cat(sys_delay_master_pending, sys_delay_slave_pending)) ] # Phase detector control self.specials += MultiReg(Cat(too_late, too_early), self._phase.status) self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x") self.comb += [ reset_lateness.eq(self.do_reset_lateness.o), self.do_reset_lateness.i.eq(self._phase_reset.re) ] # 5:10 deserialization dsr = Signal(10) self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2)) if hasattr(pad_p, "inverted"): self.sync.pix += self.d.eq(~dsr) else: self.sync.pix += self.d.eq(dsr)
def __init__(self, pad_p, pad_n, ntbits=8): self.d = Signal(10) self._dly_ctl = CSR(5) self._phase = CSRStatus(2) self._phase_reset = CSR() # # # # use 2 serdes for phase detection: master & slave serdes_m_i_nodelay = Signal() serdes_s_i_nodelay = Signal() self.specials += [ Instance( "IBUFDS_DIFF_OUT", i_I=pad_p, i_IB=pad_n, o_O=serdes_m_i_nodelay, o_OB=serdes_s_i_nodelay, ) ] delay_rst = Signal() delay_master_inc = Signal() delay_master_ce = Signal() delay_slave_inc = Signal() delay_slave_ce = Signal() # master serdes serdes_m_i_delayed = Signal() serdes_m_q = Signal(8) serdes_m_d = 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("pix1p25x"), i_LD=delay_rst, i_CE=delay_master_ce, i_LDPIPEEN=0, i_INC=delay_master_inc, i_IDATAIN=serdes_m_i_nodelay, o_DATAOUT=serdes_m_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_m_i_delayed, i_CE1=1, i_RST=ResetSignal("pix1p25x"), i_CLK=ClockSignal("pix5x"), i_CLKB=~ClockSignal("pix5x"), i_CLKDIV=ClockSignal("pix1p25x"), i_BITSLIP=0, o_Q8=serdes_m_q[0], o_Q7=serdes_m_q[1], o_Q6=serdes_m_q[2], o_Q5=serdes_m_q[3], o_Q4=serdes_m_q[4], o_Q3=serdes_m_q[5], o_Q2=serdes_m_q[6], o_Q1=serdes_m_q[7]), ] # slave serdes # idelay_value must be preloaded with a 90° phase shift but we # do it dynamically by software to support all resolutions serdes_s_i_delayed = Signal() serdes_s_q = Signal(8) serdes_s_d = 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("pix1p25x"), i_LD=delay_rst, i_CE=delay_slave_ce, i_LDPIPEEN=0, i_INC=delay_slave_inc, i_IDATAIN=serdes_s_i_nodelay, o_DATAOUT=serdes_s_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_s_i_delayed, i_CE1=1, i_RST=ResetSignal("pix1p25x"), i_CLK=ClockSignal("pix5x"), i_CLKB=~ClockSignal("pix5x"), i_CLKDIV=ClockSignal("pix1p25x"), i_BITSLIP=0, o_Q8=serdes_s_q[0], o_Q7=serdes_s_q[1], o_Q6=serdes_s_q[2], o_Q5=serdes_s_q[3], o_Q4=serdes_s_q[4], o_Q3=serdes_s_q[5], o_Q2=serdes_s_q[6], o_Q1=serdes_s_q[7]), ] # polarity if hasattr(pad_p, "inverted"): self.comb += [ serdes_m_d.eq(~serdes_m_q), serdes_s_d.eq(serdes_s_q) ] else: self.comb += [ serdes_m_d.eq(serdes_m_q), serdes_s_d.eq(~serdes_s_q) ] # datapath self.submodules.gearbox = Gearbox(8, "pix1p25x", 10, "pix") self.comb += [self.gearbox.i.eq(serdes_m_d), self.d.eq(self.gearbox.o)] # phase detector self.submodules.phase_detector = ClockDomainsRenamer("pix1p25x")( S7PhaseDetector()) self.comb += [ self.phase_detector.mdata.eq(serdes_m_d), self.phase_detector.sdata.eq(serdes_s_d) ] # phase error accumulator lateness = Signal(ntbits, reset=2**(ntbits - 1)) too_late = Signal() too_early = Signal() reset_lateness = Signal() self.comb += [ too_late.eq(lateness == (2**ntbits - 1)), too_early.eq(lateness == 0) ] self.sync.pix1p25x += [ If(reset_lateness, lateness.eq(2**(ntbits - 1))).Elif( ~too_late & ~too_early, If(self.phase_detector.dec, lateness.eq(lateness + 1)), If(self.phase_detector.inc, lateness.eq(lateness - 1))) ] # delay control self.submodules.do_delay_rst = PulseSynchronizer("sys", "pix1p25x") self.submodules.do_delay_master_inc = PulseSynchronizer( "sys", "pix1p25x") self.submodules.do_delay_master_dec = PulseSynchronizer( "sys", "pix1p25x") self.submodules.do_delay_slave_inc = PulseSynchronizer( "sys", "pix1p25x") self.submodules.do_delay_slave_dec = PulseSynchronizer( "sys", "pix1p25x") self.comb += [ delay_rst.eq(self.do_delay_rst.o), delay_master_inc.eq(self.do_delay_master_inc.o), delay_master_ce.eq(self.do_delay_master_inc.o | self.do_delay_master_dec.o), delay_slave_inc.eq(self.do_delay_slave_inc.o), delay_slave_ce.eq(self.do_delay_slave_inc.o | self.do_delay_slave_dec.o) ] self.comb += [ self.do_delay_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]), self.do_delay_master_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[1]), self.do_delay_master_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[2]), self.do_delay_slave_inc.i.eq(self._dly_ctl.re & self._dly_ctl.r[3]), self.do_delay_slave_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[4]) ] # phase detector control self.specials += MultiReg(Cat(too_late, too_early), self._phase.status) self.submodules.do_reset_lateness = PulseSynchronizer( "sys", "pix1p25x") self.comb += [ reset_lateness.eq(self.do_reset_lateness.o), self.do_reset_lateness.i.eq(self._phase_reset.re) ]
def __init__(self, comma, tx_clk_freq, check_period=6e-3): self.rxdata = Signal(20) self.restart = Signal() self.ready = Signal() check_max_val = ceil(check_period * tx_clk_freq) check_counter = Signal(max=check_max_val + 1) check = Signal() reset_check_counter = Signal() self.sync.rtio_tx += [ check.eq(0), If(reset_check_counter, check_counter.eq(check_max_val)).Else( If(check_counter == 0, check.eq(1), check_counter.eq(check_max_val)).Else( check_counter.eq(check_counter - 1))) ] checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") self.submodules += checks_reset comma_n = ~comma & 0b1111111111 comma_seen_rxclk = Signal() comma_seen = Signal() comma_seen_rxclk.attr.add("no_retiming") self.specials += MultiReg(comma_seen_rxclk, comma_seen) self.sync.rtio_rx += \ If(checks_reset.o, comma_seen_rxclk.eq(0) ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), comma_seen_rxclk.eq(1) ) error_seen_rxclk = Signal() error_seen = Signal() error_seen_rxclk.attr.add("no_retiming") self.specials += MultiReg(error_seen_rxclk, error_seen) rx1cnt = Signal(max=11) self.sync.rtio_rx += [ rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])), If(checks_reset.o, error_seen_rxclk.eq(0)).Elif( (rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6), error_seen_rxclk.eq(1)) ] fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) self.submodules += fsm fsm.act( "WAIT_COMMA", If( check, # Errors are still OK at this stage, as the transceiver # has just been reset and may output garbage data. If(comma_seen, NextState("WAIT_NOERROR")).Else(self.restart.eq(1)), checks_reset.i.eq(1))) fsm.act( "WAIT_NOERROR", If( check, If(comma_seen & ~error_seen, NextState("READY")).Else(self.restart.eq(1), NextState("WAIT_COMMA")), checks_reset.i.eq(1))) fsm.act( "READY", reset_check_counter.eq(1), self.ready.eq(1), If(error_seen, checks_reset.i.eq(1), self.restart.eq(1), NextState("WAIT_COMMA")))