def __init__(self): Endpoint.__init__(self) self.submodules.ibuf = ClockDomainsRenamer({ "write": "sys", "read": "usb_12" })(fifo.AsyncFIFOBuffered(width=8, depth=128)) xxxx_readable = Signal() self.specials.crc_readable = cdc.MultiReg(self.ibuf.readable, xxxx_readable) self.ibuf_head = CSR(8) self.ibuf_empty = CSRStatus(1) self.comb += [ self.ibuf.din.eq(self.ibuf_head.r), self.ibuf.we.eq(self.ibuf_head.re), self.ibuf_empty.status[0].eq(~xxxx_readable), ] self.obuf = self.fake
def __init__(self, usbp_raw, usbn_raw): if False: ####################################################################### # Synchronize raw USB signals # # We need to synchronize the raw USB signals with the usb_48 clock # domain. MultiReg implements a multi-stage shift register that takes # care of this for us. Without MultiReg we would have metastability # issues. # usbp = Signal(reset=1) usbn = Signal() self.specials += cdc.MultiReg(usbp_raw, usbp, n=1, reset=1) self.specials += cdc.MultiReg(usbn_raw, usbn, n=1) else: # Leave raw USB signals meta-stable. The synchronizer should clean # them up. usbp = usbp_raw usbn = usbn_raw ####################################################################### # Line State Recovery State Machine # # The receive path doesn't use a differential receiver. Because of # this there is a chance that one of the differential pairs will appear # to have changed to the new state while the other is still in the old # state. The following state machine detects transitions and waits an # extra sampling clock before decoding the state on the differential # pair. This transition period # will only ever last for one clock as # long as there is no noise on the line. If there is enough noise on # the line then the data may be corrupted and the packet will fail the # data integrity checks. # self.submodules.lsr = lsr = FSM() dpair = Signal(2) self.comb += dpair.eq(Cat(usbn, usbp)) # output signals for use by the clock recovery stage line_state_dt = Signal() line_state_dj = Signal() line_state_dk = Signal() line_state_se0 = Signal() line_state_se1 = Signal() # If we are in a transition state, then we can sample the pair and # move to the next corresponding line state. lsr.act( "DT", line_state_dt.eq(1), Case( dpair, { 0b10: NextState("DJ"), 0b01: NextState("DK"), 0b00: NextState("SE0"), 0b11: NextState("SE1") })) # If we are in a valid line state and the value of the pair changes, # then we need to move to the transition state. lsr.act("DJ", line_state_dj.eq(1), If(dpair != 0b10, NextState("DT"))) lsr.act("DK", line_state_dk.eq(1), If(dpair != 0b01, NextState("DT"))) lsr.act("SE0", line_state_se0.eq(1), If(dpair != 0b00, NextState("DT"))) lsr.act("SE1", line_state_se1.eq(1), If(dpair != 0b11, NextState("DT"))) ####################################################################### # Clock and Data Recovery # # The DT state from the line state recovery state machine is used to align to # transmit clock. The line state is sampled in the middle of the bit time. # # Example of signal relationships # ------------------------------- # line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ # line_state_valid ________----____________----____________----________----____ # bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2 # # We 4x oversample, so make the line_state_phase have # 4 possible values. line_state_phase = Signal(2) self.line_state_valid = Signal() self.line_state_dj = Signal() self.line_state_dk = Signal() self.line_state_se0 = Signal() self.line_state_se1 = Signal() self.sync += [ self.line_state_valid.eq(line_state_phase == 1), If( line_state_dt, # re-align the phase with the incoming transition line_state_phase.eq(0), # make sure we never assert valid on a transition self.line_state_valid.eq(0), ).Else( # keep tracking the clock by incrementing the phase line_state_phase.eq(line_state_phase + 1)), # flop all the outputs to help with timing self.line_state_dj.eq(line_state_dj), self.line_state_dk.eq(line_state_dk), self.line_state_se0.eq(line_state_se0), self.line_state_se1.eq(line_state_se1), ]
def __init__(self, tx, auto_crc=True): self.submodules.tx = tx self.i_pkt_start = Signal() self.o_pkt_end = Signal() self.i_pid = Signal(4) self.i_data_payload = Signal(8) self.i_data_ready = Signal() self.o_data_ack = Signal() o_oe12 = Signal() self.specials += cdc.MultiReg(tx.o_oe, o_oe12, odomain="usb_12", n=1) pid = Signal(4) fsm = FSM() self.submodules.fsm = fsm = ClockDomainsRenamer("usb_12")(fsm) fsm.act( 'IDLE', NextValue(tx.i_oe, self.i_pkt_start), If( self.i_pkt_start, # If i_pkt_start is set, then send the next packet. # We pre-queue the SYNC byte here to cut down on latency. NextState('QUEUE_SYNC'), ).Else(NextValue(tx.i_oe, 0), )) # Send the QUEUE_SYNC byte fsm.act( 'QUEUE_SYNC', # The PID might change mid-sync, because we're still figuring # out what the response ought to be. NextValue(pid, self.i_pid), tx.i_data_payload.eq(1), If( tx.o_data_strobe, NextState('QUEUE_PID'), ), ) # Send the PID byte fsm.act( 'QUEUE_PID', tx.i_data_payload.eq(Cat(pid, pid ^ 0b1111)), If( tx.o_data_strobe, If( pid & PIDTypes.TYPE_MASK == PIDTypes.HANDSHAKE, NextState('WAIT_TRANSMIT'), ).Elif( pid & PIDTypes.TYPE_MASK == PIDTypes.DATA, NextState('QUEUE_DATA0'), ).Else(NextState('ERROR'), ), ), ) nextstate = 'WAIT_TRANSMIT' if auto_crc: nextstate = 'QUEUE_CRC0' fsm.act( 'QUEUE_DATA0', If( ~self.i_data_ready, NextState(nextstate), ).Else(NextState('QUEUE_DATAn'), ), ) # Keep transmitting data bytes until the i_data_ready signal is not # high on a o_data_strobe event. fsm.act( 'QUEUE_DATAn', tx.i_data_payload.eq(self.i_data_payload), self.o_data_ack.eq(tx.o_data_strobe), If( ~self.i_data_ready, NextState(nextstate), ), ) if auto_crc: crc = TxParallelCrcGenerator( crc_width=16, data_width=8, polynomial=0b1000000000000101, # polynomial = (16, 15, 2, 0) initial=0b1111111111111111, # seed = 0xFFFF ) self.submodules.crc = crc = ClockDomainsRenamer("usb_12")(crc) self.comb += [ crc.i_data_payload.eq(self.i_data_payload), crc.reset.eq(fsm.ongoing('QUEUE_PID')), If( fsm.ongoing('QUEUE_DATAn'), crc.i_data_strobe.eq(tx.o_data_strobe), ), ] fsm.act( 'QUEUE_CRC0', tx.i_data_payload.eq(crc.o_crc[:8]), If( tx.o_data_strobe, NextState('QUEUE_CRC1'), ), ) fsm.act( 'QUEUE_CRC1', tx.i_data_payload.eq(crc.o_crc[8:]), If( tx.o_data_strobe, NextState('WAIT_TRANSMIT'), ), ) fsm.act( 'WAIT_TRANSMIT', NextValue(tx.i_oe, 0), If( ~o_oe12, self.o_pkt_end.eq(1), NextState('IDLE'), ), ) fsm.act('ERROR')
def __init__(self): self.i_bit_strobe = Signal() self.i_data_payload = Signal(8) self.o_data_strobe = Signal() self.i_oe = Signal() self.o_usbp = Signal() self.o_usbn = Signal() self.o_oe = Signal() self.o_pkt_end = Signal() tx_pipeline_fsm = FSM() self.submodules.tx_pipeline_fsm = ClockDomainsRenamer("usb_12")( tx_pipeline_fsm) shifter = TxShifter(width=8) self.submodules.shifter = ClockDomainsRenamer("usb_12")(shifter) bitstuff = TxBitstuffer() self.submodules.bitstuff = ClockDomainsRenamer("usb_12")(bitstuff) nrzi = TxNRZIEncoder() self.submodules.nrzi = ClockDomainsRenamer("usb_48")(nrzi) sync_pulse = Signal(8) self.fit_dat = fit_dat = Signal() self.fit_oe = fit_oe = Signal() da_reset_shifter = Signal() da_reset_bitstuff = Signal( ) # Need to reset the bit stuffer 1 cycle after the shifter. stall = Signal() # These signals are set during the sync pulse sp_reset_bitstuff = Signal() sp_reset_shifter = Signal() sp_bit = Signal() sp_o_data_strobe = Signal() # 12MHz domain da_stalled_reset = Signal() bitstuff_valid_data = Signal() # Keep a Gray counter around to smoothly transition between states state_gray = Signal(2) state_data = Signal() state_sync = Signal() self.comb += [ shifter.i_data.eq(self.i_data_payload), # Send a data strobe when we're two bits from the end of the sync pulse. # This is because the pipeline takes two bit times, and we want to ensure the pipeline # has spooled up enough by the time we're there. shifter.reset.eq(da_reset_shifter | sp_reset_shifter), shifter.ce.eq(~stall), bitstuff.reset.eq(da_reset_bitstuff), bitstuff.i_data.eq(shifter.o_data), stall.eq(bitstuff.o_stall), sp_bit.eq(sync_pulse[0]), sp_reset_bitstuff.eq(sync_pulse[0]), # The shifter has one clock cycle of latency, so reset it # one cycle before the end of the sync byte. sp_reset_shifter.eq(sync_pulse[1]), sp_o_data_strobe.eq(sync_pulse[5]), state_data.eq(state_gray[0] & state_gray[1]), state_sync.eq(state_gray[0] & ~state_gray[1]), fit_oe.eq(state_data | state_sync), fit_dat.eq((state_data & shifter.o_data & ~bitstuff.o_stall) | sp_bit), self.o_data_strobe.eq((state_data & shifter.o_get & ~stall & self.i_oe) | sp_o_data_strobe), ] # If we reset the shifter, then o_empty will go high on the next cycle. # self.sync.usb_12 += [ # If the shifter runs out of data, percolate the "reset" signal to the # shifter, and then down to the bitstuffer. # da_reset_shifter.eq(~stall & shifter.o_empty & ~da_stalled_reset), # da_stalled_reset.eq(da_reset_shifter), # da_reset_bitstuff.eq(~stall & da_reset_shifter), bitstuff_valid_data.eq(~stall & shifter.o_get & self.i_oe), ] tx_pipeline_fsm.act( 'IDLE', If( self.i_oe, NextState('SEND_SYNC'), NextValue(sync_pulse, 1 << 7), NextValue(state_gray, 0b01), ).Else(NextValue(state_gray, 0b00), )) tx_pipeline_fsm.act( 'SEND_SYNC', NextValue(sync_pulse, sync_pulse >> 1), If( sync_pulse[0], NextState('SEND_DATA'), NextValue(state_gray, 0b11), ).Else(NextValue(state_gray, 0b01), ), ) tx_pipeline_fsm.act( 'SEND_DATA', If( ~self.i_oe & shifter.o_empty & ~bitstuff.o_stall, If(bitstuff.o_will_stall, NextState('STUFF_LAST_BIT')).Else( NextValue(state_gray, 0b10), NextState('IDLE'), )).Else(NextValue(state_gray, 0b11), ), ) tx_pipeline_fsm.act( 'STUFF_LAST_BIT', NextValue(state_gray, 0b10), NextState('IDLE'), ) # 48MHz domain # NRZI encoding nrzi_dat = Signal() nrzi_oe = Signal() # Cross the data from the 12MHz domain to the 48MHz domain cdc_dat = cdc.MultiReg(fit_dat, nrzi_dat, odomain="usb_48", n=3) cdc_oe = cdc.MultiReg(fit_oe, nrzi_oe, odomain="usb_48", n=3) self.specials += [cdc_dat, cdc_oe] self.comb += [ nrzi.i_valid.eq(self.i_bit_strobe), nrzi.i_data.eq(nrzi_dat), nrzi.i_oe.eq(nrzi_oe), self.o_usbp.eq(nrzi.o_usbp), self.o_usbn.eq(nrzi.o_usbn), self.o_oe.eq(nrzi.o_oe), ]