def elaborate(self, platform): m = Module() with m.If(self.i_hlclk): m.d.sync += [ self.r_hline.eq(self.r_hline + 1), self.r_hline_count.eq(self.r_hline_count + 1), ] with m.FSM() as fsm: with m.State("SYNC"): with m.If(self.r_hline_count == self.syncv_vs): m.d.sync += self.r_hline_count.eq(1) m.next = "BACK-PORCH" with m.State("BACK-PORCH"): with m.If(self.r_hline_count == (self.syncv_vbp + self.syncv_vbpe)): m.d.sync += self.r_hline_count.eq(1) m.next = "DISPLAY" with m.State("DISPLAY"): with m.If(self.r_hline_count == self.syncv_vdp): m.d.sync += self.r_hline.eq(1) m.d.sync += self.r_hline_count.eq(1) m.next = "FRONT-PORCH" with m.State("FRONT-PORCH"): with m.If(self.r_hline_count == (self.syncv_vfp + self.syncv_vfpe)): m.d.sync += self.r_hline_count.eq(1) m.d.sync += self.o_odd.eq(~self.o_odd) m.next = "SYNC" return m
def elaborate(self, platform): m = Module() crc = Signal(32) self.crctable = Memory(32, 256, make_crc32_table()) table_port = self.crctable.read_port() m.submodules += table_port m.d.comb += [ self.crc_out.eq(crc ^ 0xFFFFFFFF), self.crc_match.eq(crc == 0xDEBB20E3), table_port.addr.eq(crc ^ self.data), ] with m.FSM(): with m.State("RESET"): m.d.sync += crc.eq(0xFFFFFFFF) m.next = "IDLE" with m.State("IDLE"): with m.If(self.reset): m.next = "RESET" with m.Elif(self.data_valid): m.next = "BUSY" with m.State("BUSY"): with m.If(self.reset): m.next = "RESET" m.d.sync += crc.eq(table_port.data ^ (crc >> 8)) m.next = "IDLE" return m
def elaborate(self, platform): m = Module() rx_port = self.user_rx_mem.read_port() tx_port = self.user_tx_mem.write_port() m.submodules += [self.mem_r_port, self.mem_w_port, rx_port, tx_port] led1 = platform.request("user_led", 0) led2 = platform.request("user_led", 1) m.d.comb += [ tx_port.addr.eq(0), tx_port.en.eq(0), tx_port.data.eq(0), rx_port.addr.eq(0), ] m.d.sync += [ led1.eq(rx_port.data & 1), led2.eq((rx_port.data & 2) >> 1), ] with m.FSM(): with m.State("IDLE"): m.d.sync += self.transmit_packet.eq(0) with m.If(self.packet_received): m.next = "RX" with m.State("RX"): with m.If(self.transmit_ready): m.d.sync += self.transmit_packet.eq(1) m.next = "IDLE" return m
def elaborate(self, platform): m = Module() mac = [Signal(8) for _ in range(6)] m.d.sync += self.mac_match.eq( reduce(operator.and_, [(mac[idx] == self.mac_addr[idx]) | (mac[idx] == 0xFF) for idx in range(6)])) with m.FSM(): with m.State("RESET"): m.d.sync += [mac[idx].eq(0) for idx in range(6)] with m.If(~self.reset): m.next = "BYTE0" for idx in range(6): next_state = f"BYTE{idx+1}" if idx < 5 else "DONE" with m.State(f"BYTE{idx}"): m.d.sync += mac[idx].eq(self.data) with m.If(self.reset): m.next = "RESET" with m.Elif(self.data_valid): m.next = next_state with m.State("DONE"): with m.If(self.reset): m.next = "RESET" return m
def elaborate(self, platform): m = Module() # This state machine recognizes sequences of 6 bits and drops the 7th # bit. The fsm implements a counter in a series of several states. # This is intentional to help absolutely minimize the levels of logic # used. drop_bit = Signal(1) with m.FSM(domain="usb_io"): for i in range(6): with m.State(f"D{i}"): with m.If(self.i_valid): with m.If(self.i_data): # Receiving '1' increments the bitstuff counter. m.next = (f"D{i + 1}") with m.Else(): # Receiving '0' resets the bitstuff counter. m.next = "D0" with m.State("D6"): with m.If(self.i_valid): m.d.comb += drop_bit.eq(1) # Reset the bitstuff counter, drop the data. m.next = "D0" m.d.usb_io += [ self.o_data.eq(self.i_data), self.o_stall.eq(drop_bit | ~self.i_valid), self.o_error.eq(drop_bit & self.i_data & self.i_valid), ] return m
def elaborate(self, platform): m = Module() interface = self.interface # Create convenience aliases for our interface components. setup = interface.setup handshake = interface.handshake with m.FSM(domain="usb"): # IDLE -- not handling any active request with m.State('IDLE'): # If we've received a new setup packet, handle it. # TODO: limit this to standard requests with m.If(setup.received): # Select which standard packet we're going to handler. m.next = 'UNHANDLED' # UNHANDLED -- we've received a request we're not prepared to handle with m.State('UNHANDLED'): # When we next have an opportunity to stall, do so, # and then return to idle. with m.If(interface.data_requested | interface.status_requested): m.d.comb += handshake.stall.eq(1) m.next = 'IDLE' return m
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = self.serdes # The symbol table reads the corresponding symbols for each # symbol in PACKET and outputs them on tx_data m.submodules.symboltable = symboltable = SymbolTable( table=pack_mem(TABLE, width=20), packet=Memory(width=16, depth=len(PACKET), init=[int(i) for i in np.array(PACKET) * 5000 / 20]), samples_per_symbol=int(5e9 / 1e6), tx_domain="tx") m.d.comb += [ symboltable.packet_length.eq(len(PACKET)), serdes.tx_data.eq(symboltable.tx_data) ] # Quick state machine to transmit and then wait a bit before # transmitting again counter = Signal(32) with m.FSM(): with m.State("START"): m.d.sync += symboltable.tx_reset.eq(1) m.next = "WAIT_DONE" with m.State("WAIT_DONE"): m.d.sync += symboltable.tx_reset.eq(0) with m.If(symboltable.tx_done): m.d.sync += counter.eq(0) m.next = "PAUSE" with m.State("PAUSE"): m.d.sync += counter.eq(counter + 1) with m.If(counter >= int(1e4)): m.next = "START" return m
def elaborate(self, platform: Platform) -> Module: m = Module() # Signal defaults m.d.comb += self.ft.oe.o.eq(0) m.d.comb += self.ft.write.o.eq(0) m.d.comb += self.ft.read.o.eq(0) with m.FSM(): with m.State("READY"): # If there is data to read, we read it first before entering the write state with m.If(self.ft.rxf.i): m.d.comb += self.ft.oe.o.eq(1) m.d.comb += self.ft.data.oe.eq(0) m.d.comb += self.ft.be.oe.eq(0) m.next = "READ" with m.Elif(self.ft.txe.i & self.input_valid): m.d.comb += self.ft.data.oe.eq(1) m.d.comb += self.ft.be.oe.eq(1) m.next = "WRITE" with m.State("READ"): m.d.comb += self.ft.oe.o.eq(1) # Set pins in correct direction (input) m.d.comb += self.ft.data.oe.eq(0) m.d.comb += self.ft.be.oe.eq(0) # Connect FIFO m.d.comb += self.output_payload.eq(self.ft.data.i) m.d.comb += self.output_valid.eq(self.ft.rxf.i) m.d.comb += self.ft.read.o.eq(self.output_ready) with m.If(~self.ft.rxf.i): m.next = "READY" with m.State("WRITE"): # Set pins in correct direction (output) m.d.comb += self.ft.data.oe.eq(1) m.d.comb += self.ft.be.oe.eq(1) # All bytes are valid m.d.comb += self.ft.oe.o.eq(0) m.d.comb += self.ft.be.o.eq(0b11) # Connect FIFO m.d.comb += self.ft.data.o.eq(self.input_payload) m.d.comb += self.input_ready.eq(self.ft.txe.i) m.d.comb += self.ft.write.o.eq(self.input_valid) # TODO: Should we go to ready if there is data to read, or wait until write is done? with m.If(~self.ft.txe.i | ~self.input_valid): m.next = "READY" return m
def elaborate(self, platform): m = Module() # Register input data on the data_valid signal data_reg = Signal(8) with m.FSM() as fsm: m.d.comb += [ self.ready.eq(fsm.ongoing("IDLE") | fsm.ongoing("NIBBLE4")), self.txen.eq(~fsm.ongoing("IDLE")), ] with m.State("IDLE"): m.d.comb += [ self.txd0.eq(0), self.txd1.eq(0), ] m.d.sync += data_reg.eq(self.data) with m.If(self.data_valid): m.next = "NIBBLE1" with m.State("NIBBLE1"): m.d.comb += [ self.txd0.eq(data_reg[0]), self.txd1.eq(data_reg[1]), ] m.next = "NIBBLE2" with m.State("NIBBLE2"): m.d.comb += [ self.txd0.eq(data_reg[2]), self.txd1.eq(data_reg[3]), ] m.next = "NIBBLE3" with m.State("NIBBLE3"): m.d.comb += [ self.txd0.eq(data_reg[4]), self.txd1.eq(data_reg[5]), ] m.next = "NIBBLE4" with m.State("NIBBLE4"): m.d.comb += [ self.txd0.eq(data_reg[6]), self.txd1.eq(data_reg[7]), ] m.d.sync += data_reg.eq(self.data) with m.If(self.data_valid): m.next = "NIBBLE1" with m.Else(): m.next = "IDLE" return m
def elaborate(self, platform: Platform) -> Module: m = Module() # TODO: Add async FIFOs internally # m.submodules.write_fifo = write_fifo = AsyncFIFOBuffered(...) # m.submodules.read_fifo = read_fifo = AsyncFIFOBuffered(...) m.d.comb += self.ft_data.eq(self.ft_override) # Signal defaults m.d.comb += self.ft_oe.eq(0) m.d.comb += self.ft_write.eq(0) m.d.comb += self.ft_read.eq(0) with m.FSM(): with m.State("READY"): # If there is data to read, we read it first before entering the write state with m.If(self.ft_rxf): m.d.comb += self.ft_oe.eq(1) m.next = "READ" with m.Elif(self.ft_txe & self.input_valid): m.next = "WRITE" with m.State("READ"): m.d.comb += self.ft_oe.eq(1) # Connect FIFO, TODO: Add support for IO on the data and be lines m.d.comb += self.output_payload.eq(self.ft_data) m.d.comb += self.output_valid.eq(self.ft_rxf) m.d.comb += self.ft_read.eq(self.output_ready) with m.If(~self.ft_rxf): m.next = "READY" with m.State("WRITE"): m.d.comb += self.ft_be.eq(0b11) # Connect FIFO, TODO: Add support for IO on the data and be lines m.d.comb += self.ft_data.eq(self.input_payload) m.d.comb += self.input_ready.eq(self.ft_txe) m.d.comb += self.ft_write.eq(self.input_valid) # TODO: Should we go to ready if there is data to read, or wait until write is done? with m.If(~self.ft_txe | ~self.input_valid): m.next = "READY" return m
def elaborate(self, platform): m = Module() m.submodules.crc = crc = CRC32() m.submodules.mac_match = mac_match = MACAddressMatch(self.mac_addr) m.submodules.rxbyte = rxbyte = RMIIRxByte(self.crs_dv, self.rxd0, self.rxd1) adr = Signal(self.write_port.addr.nbits) with m.FSM() as fsm: m.d.comb += [ self.write_port.addr.eq(adr), self.write_port.data.eq(rxbyte.data), self.write_port.en.eq(rxbyte.data_valid), crc.data.eq(rxbyte.data), crc.data_valid.eq(rxbyte.data_valid), crc.reset.eq(fsm.ongoing("IDLE")), mac_match.data.eq(rxbyte.data), mac_match.data_valid.eq(rxbyte.data_valid), mac_match.reset.eq(fsm.ongoing("IDLE")), ] # Idle until we see data valid with m.State("IDLE"): m.d.sync += self.rx_len.eq(0) m.d.sync += self.rx_valid.eq(0) with m.If(rxbyte.dv): m.d.sync += self.rx_offset.eq(adr) m.next = "DATA" # Save incoming data to memory with m.State("DATA"): with m.If(rxbyte.data_valid): m.d.sync += adr.eq(adr + 1) m.d.sync += self.rx_len.eq(self.rx_len + 1) with m.Elif(~rxbyte.dv): m.next = "EOF" with m.State("EOF"): with m.If(crc.crc_match & mac_match.mac_match): m.d.sync += self.rx_valid.eq(1) m.next = "IDLE" return m
def elaborate(self, platform): m = Module() stuff_bit = Signal() with m.FSM(domain="usb"): for i in range(5): with m.State(f"D{i}"): # Receiving '1' increments the bitstuff counter. with m.If(self.i_data): m.next = f"D{i+1}" # Receiving '0' resets the bitstuff counter. with m.Else(): m.next = "D0" with m.State("D5"): with m.If(self.i_data): # There's a '1', so indicate we might stall on the next loop. m.d.comb += self.o_will_stall.eq(1), m.next = "D6" with m.Else(): m.next = "D0" with m.State("D6"): m.d.comb += stuff_bit.eq(1) m.next = "D0" m.d.comb += [ self.o_stall.eq(stuff_bit) ] # flop outputs with m.If(stuff_bit): m.d.usb += self.o_data.eq(0), with m.Else(): m.d.usb += self.o_data.eq(self.i_data) return m
def elaborate(self, platform): m = Module() pkt_start = Signal() pkt_active = Signal() pkt_end = Signal() with m.FSM(domain="usb_io"): for i in range(5): with m.State(f"D{i}"): with m.If(self.i_valid): with m.If(self.i_data | self.i_se0): # Receiving '1' or SE0 early resets the packet start counter. m.next = "D0" with m.Else(): # Receiving '0' increments the packet start counter. m.next = f"D{i + 1}" with m.State("D5"): with m.If(self.i_valid): with m.If(self.i_se0): m.next = "D0" # once we get a '1', the packet is active with m.Elif(self.i_data): m.d.comb += pkt_start.eq(1) m.next = "PKT_ACTIVE" with m.State("PKT_ACTIVE"): m.d.comb += pkt_active.eq(1) with m.If(self.i_valid & self.i_se0): m.d.comb += [pkt_active.eq(0), pkt_end.eq(1)] m.next = "D0" # pass all of the outputs through a pipe stage m.d.comb += [ self.o_pkt_start.eq(pkt_start), self.o_pkt_active.eq(pkt_active), self.o_pkt_end.eq(pkt_end), ] return m
def elaborate(self, platform): m = Module() for i in range(self.width): m.submodules["pipe{:02}".format(i)] = pipe = PixelPipeline() self._add_pipeline_settings(m, pipe, self.pipes[i]) with m.FSM(): with m.State("READ"): with m.Switch(self.i_address): with m.Case(Register.ALPHA_1): # TODO: Multiple rendering contexts with m.Case(Register.DIMX): for x in range(4): for y in range(4): index = 16*x + 4*y m.d.sync += self.i_dimx_dm[x][y].eq(self.i_data[index:index+3]) return m
def elaborate(self, platform): m = Module() counter = Signal(max=self.nclks) with m.FSM() as fsm: m.d.comb += self.pulse.eq(fsm.ongoing("STRETCH")) with m.State("WAIT"): m.d.sync += counter.eq(0) with m.If(self.trigger): m.next = "STRETCH" with m.State("STRETCH"): with m.If(counter == self.nclks - 1): m.next = "WAIT" with m.Else(): m.d.sync += counter.eq(counter + 1) return m
def elaborate(self, platform): m = Module() # Counter that stores how many cycles we've spent in reset. cycles_in_reset = Signal(range(0, self.reset_length_cycles)) reset_state = 'RESETTING' if self.power_on_reset else 'IDLE' with m.FSM(reset=reset_state, domain='sync') as fsm: # Drive the PHY reset whenever we're in the RESETTING cycle. m.d.comb += [ self.phy_reset.eq(fsm.ongoing('RESETTING')), self.phy_stop.eq(~fsm.ongoing('IDLE')) ] with m.State('IDLE'): m.d.sync += cycles_in_reset.eq(0) # Wait for a reset request. with m.If(self.trigger): m.next = 'RESETTING' # RESETTING: hold the reset line active for the given amount of time with m.State('RESETTING'): m.d.sync += cycles_in_reset.eq(cycles_in_reset + 1) with m.If(cycles_in_reset + 1 == self.reset_length_cycles): m.d.sync += cycles_in_reset.eq(0) m.next = 'DEFERRING_STARTUP' # DEFERRING_STARTUP: Produce a signal that will defer startup for # the provided amount of time. This allows line state to stabilize # before the PHY will start interacting with us. with m.State('DEFERRING_STARTUP'): m.d.sync += cycles_in_reset.eq(cycles_in_reset + 1) with m.If(cycles_in_reset + 1 == self.stop_length_cycles): m.d.sync += cycles_in_reset.eq(0) m.next = 'IDLE' return m
def elaborate(self, platform: Platform) -> Module: m = Module() with m.FSM(reset="IDLE") as self.fsm: with m.State("IDLE"): self.Idle(m) with m.State("START"): self.Start(m) with m.State("DATA"): self.Data(m) with m.State("STOP"): self.Stop(m) with m.State("DONE"): self.Done(m) # with m.State("ERROR"): # self.Error(m) return m
def elaborate(self, platform): m = Module() # Transmit byte counter tx_idx = Signal(self.read_port.addr.nbits) # Transmit length latch tx_len = Signal(11) # Transmit offset latch tx_offset = Signal(self.read_port.addr.nbits) m.submodules.crc = crc = CRC32() m.submodules.txbyte = txbyte = RMIITxByte(self.txen, self.txd0, self.txd1) with m.FSM() as fsm: m.d.comb += [ self.read_port.addr.eq(tx_idx + tx_offset), crc.data.eq(txbyte.data), crc.reset.eq(fsm.ongoing("IDLE")), crc.data_valid.eq((fsm.ongoing("DATA") | fsm.ongoing("PAD")) & txbyte.ready), self.tx_ready.eq(fsm.ongoing("IDLE")), txbyte.data_valid.eq(~(fsm.ongoing("IDLE") | fsm.ongoing("IPG"))), ] with m.State("IDLE"): m.d.comb += txbyte.data.eq(0) m.d.sync += [ tx_idx.eq(0), tx_offset.eq(self.tx_offset), tx_len.eq(self.tx_len), ] with m.If(self.tx_start): m.next = "PREAMBLE" with m.State("PREAMBLE"): m.d.comb += txbyte.data.eq(0x55) with m.If(txbyte.ready): with m.If(tx_idx == 6): m.d.sync += tx_idx.eq(0) m.next = "SFD" with m.Else(): m.d.sync += tx_idx.eq(tx_idx + 1) with m.State("SFD"): m.d.comb += txbyte.data.eq(0xD5) with m.If(txbyte.ready): m.next = "DATA" with m.State("DATA"): m.d.comb += txbyte.data.eq(self.read_port.data) with m.If(txbyte.ready): m.d.sync += tx_idx.eq(tx_idx + 1) with m.If(tx_idx == tx_len - 1): with m.If(tx_len < 60): m.next = "PAD" with m.Else(): m.next = "FCS1" with m.State("PAD"): m.d.comb += txbyte.data.eq(0x00) with m.If(txbyte.ready): m.d.sync += tx_idx.eq(tx_idx + 1) with m.If(tx_idx == 59): m.next = "FCS1" with m.State("FCS1"): m.d.comb += txbyte.data.eq(crc.crc_out[0:8]) with m.If(txbyte.ready): m.next = "FCS2" with m.State("FCS2"): m.d.comb += txbyte.data.eq(crc.crc_out[8:16]) with m.If(txbyte.ready): m.next = "FCS3" with m.State("FCS3"): m.d.comb += txbyte.data.eq(crc.crc_out[16:24]) with m.If(txbyte.ready): m.next = "FCS4" with m.State("FCS4"): m.d.comb += txbyte.data.eq(crc.crc_out[24:32]) with m.If(txbyte.ready): m.d.sync += tx_idx.eq(0) m.next = "IPG" with m.State("IPG"): m.d.sync += tx_idx.eq(tx_idx + 1) with m.If(tx_idx == 48): m.next = "IDLE" return m
def elaborate(self, platform): m = Module() # Sample RMII signals on rising edge of ref_clk crs_dv_reg = Signal() rxd_reg = Signal(2) m.d.sync += [ crs_dv_reg.eq(self.crs_dv), rxd_reg.eq(Cat(self.rxd0, self.rxd1)), ] with m.FSM(): with m.State("IDLE"): m.d.sync += [ self.crs.eq(0), self.dv.eq(0), self.data_valid.eq(0), ] with m.If(crs_dv_reg & (rxd_reg == 0b01)): m.next = "PREAMBLE_SFD" with m.State("PREAMBLE_SFD"): m.d.sync += [ self.crs.eq(1), self.dv.eq(1), self.data_valid.eq(0), ] with m.If(rxd_reg == 0b11): m.next = "NIBBLE1" with m.Elif(rxd_reg != 0b01): m.next = "IDLE" with m.State("NIBBLE1"): m.d.sync += [ self.data[0:2].eq(rxd_reg), self.data_valid.eq(0), ] with m.If(self.dv): m.d.sync += self.crs.eq(crs_dv_reg) m.next = "NIBBLE2" with m.Else(): m.next = "IDLE" with m.State("NIBBLE2"): m.d.sync += [ self.data[2:4].eq(rxd_reg), self.data_valid.eq(0), ] with m.If(self.dv): m.d.sync += self.dv.eq(crs_dv_reg) m.next = "NIBBLE3" with m.Else(): m.next = "IDLE" with m.State("NIBBLE3"): m.d.sync += [ self.data[4:6].eq(rxd_reg), self.data_valid.eq(0), ] with m.If(self.dv): m.d.sync += self.crs.eq(crs_dv_reg) m.next = "NIBBLE4" with m.Else(): m.next = "IDLE" with m.State("NIBBLE4"): m.d.sync += [ self.data[6:8].eq(rxd_reg), self.data_valid.eq(0), ] with m.If(self.dv): m.d.sync += [ self.dv.eq(crs_dv_reg), self.data_valid.eq(1), ] m.next = "NIBBLE1" with m.Else(): m.d.sync += self.data_valid.eq(1), m.next = "IDLE" return m
def elaborate(self, platform): m = Module() m.submodules.bridge = self._bridge # Shortcuts to our components. token = self.interface.tokenizer tx = self.interface.tx handshakes_out = self.interface.handshakes_out # # Core FIFO. # # Create our FIFO; and set it to be cleared whenever the user requests. m.submodules.fifo = fifo = \ ResetInserter(self.reset.w_stb)(SyncFIFOBuffered(width=8, depth=self.max_packet_size)) m.d.comb += [ # Whenever the user DATA register is written to, add the relevant data to our FIFO. fifo.w_en .eq(self.data.w_stb), fifo.w_data .eq(self.data.w_data), ] # Keep track of the amount of data in our FIFO. bytes_in_fifo = Signal(range(0, self.max_packet_size + 1)) # If we're clearing the whole FIFO, reset our data count. with m.If(self.reset.w_stb): m.d.usb += bytes_in_fifo.eq(0) # Keep track of our FIFO's data count as data is added or removed. increment = fifo.w_en & fifo.w_rdy decrement = fifo.r_en & fifo.r_rdy with m.Elif(increment & ~decrement): m.d.usb += bytes_in_fifo.eq(bytes_in_fifo + 1) with m.Elif(decrement & ~increment): m.d.usb += bytes_in_fifo.eq(bytes_in_fifo - 1) # # Register updates. # # Active endpoint number. with m.If(self.epno.w_stb): m.d.usb += self.epno.r_data.eq(self.epno.w_data) # Keep track of which endpoints are stalled. endpoint_stalled = Array(Signal() for _ in range(16)) # Set the value of our endpoint `stall` based on our `stall` register... with m.If(self.stall.w_stb): m.d.usb += endpoint_stalled[self.epno.r_data].eq(self.stall.w_data) # ... but clear our endpoint `stall` when we get a SETUP packet. with m.If(token.is_setup & token.new_token): m.d.usb += endpoint_stalled[token.endpoint].eq(0) # Manual data toggle control. # TODO: Remove this in favor of automated tracking? m.d.comb += self.interface.tx_pid_toggle.eq(self.pid.r_data) with m.If(self.pid.w_stb): m.d.usb += self.pid.r_data.eq(self.pid.w_data) # # Status registers. # m.d.comb += [ self.have.r_data .eq(fifo.r_rdy) ] # # Control logic. # # Logic shorthand. new_in_token = (token.is_in & token.ready_for_response) endpoint_matches = (token.endpoint == self.epno.r_data) stalled = endpoint_stalled[token.endpoint] with m.FSM(domain='usb') as f: # Drive our IDLE line based on our FSM state. m.d.comb += self.idle.r_data.eq(f.ongoing('IDLE')) # IDLE -- our CPU hasn't yet requested that we send data. # We'll wait for it to do so, and NAK any packets that arrive. with m.State("IDLE"): # If we get an IN token... with m.If(new_in_token): # STALL it, if the endpoint is STALL'd... with m.If(stalled): m.d.comb += handshakes_out.stall.eq(1) # Otherwise, NAK. with m.Else(): m.d.comb += handshakes_out.nak.eq(1) # If the user request that we send data, "prime" the endpoint. # This means we have data to send, but are just waiting for an IN token. with m.If(self.epno.w_stb & ~stalled): m.next = "PRIMED" # PRIMED -- our CPU has provided data, but we haven't been sent an IN token, yet. # Await that IN token. with m.State("PRIMED"): with m.If(new_in_token): # If the target endpoint is STALL'd, reply with STALL no matter what. with m.If(stalled): m.d.comb += handshakes_out.stall.eq(1) # If we have a new IN token to our endpoint, move to responding to it. with m.Elif(endpoint_matches): # If there's no data in our endpoint, send a ZLP. with m.If(~fifo.r_rdy): m.next = "SEND_ZLP" # Otherwise, send our data, starting with our first byte. with m.Else(): m.d.usb += tx.first.eq(1) m.next = "SEND_DATA" # Otherwise, we don't have a response; NAK the packet. with m.Else(): m.d.comb += handshakes_out.nak.eq(1) # SEND_ZLP -- we're now now ready to respond to an IN token with a ZLP. # Send our response. with m.State("SEND_ZLP"): m.d.comb += [ tx.valid .eq(1), tx.last .eq(1) ] m.next = 'IDLE' # SEND_DATA -- we're now ready to respond to an IN token to our endpoint. # Send our response. with m.State("SEND_DATA"): last_packet = (bytes_in_fifo == 1) m.d.comb += [ tx.valid .eq(1), tx.last .eq(last_packet), # Drive our transmit data directly from our FIFO... tx.payload .eq(fifo.r_data), # ... and advance our FIFO each time a data byte is transmitted. fifo.r_en .eq(tx.ready) ] # After we've sent a byte, drop our first flag. with m.If(tx.ready): m.d.usb += tx.first.eq(0) # Once we transmit our last packet, we're done transmitting. Move back to IDLE. with m.If(last_packet & tx.ready): m.next = 'IDLE' return DomainRenamer({"sync": "usb"})(m)
def elaborate(self, platform): m = Module() # Shortcuts. tx = self.interface.tx tokenizer = self.interface.tokenizer # Grab a copy of the relevant signal that's in our USB domain; synchronizing if we need to. if self._signal_domain == "usb": target_signal = self.signal else: target_signal = synchronize(m, self.signal, o_domain="usb") # Store a latched version of our signal, captured before we start a transmission. latched_signal = Signal.like(self.signal) # Grab an byte-indexable reference into our signal. bytes_in_signal = (self._width + 7) // 8 signal_bytes = Array(latched_signal[n * 8:n * 8 + 8] for n in range(bytes_in_signal)) # Store how many bytes we've transmitted. bytes_transmitted = Signal(range(0, bytes_in_signal + 1)) # # Data transmission logic. # # If this signal is big endian, send them in reading order; otherwise, index our multiplexer in reverse. # Note that our signal is captured little endian by default, due the way we use Array() above. If we want # big endian; then we'll flip it. if self._endianness == "little": index_to_transmit = bytes_transmitted else: index_to_transmit = bytes_in_signal - bytes_transmitted - 1 # Always transmit the part of the latched signal byte that corresponds to our m.d.comb += tx.payload.eq(signal_bytes[index_to_transmit]) # # Core control FSM. # endpoint_number_matches = (tokenizer.endpoint == self._endpoint_number) targeting_endpoint = endpoint_number_matches & tokenizer.is_in packet_requested = targeting_endpoint & tokenizer.ready_for_response with m.FSM(domain="usb"): # IDLE -- we've not yet gotten an token requesting data. Wait for one. with m.State('IDLE'): # Once we're ready to send a response... with m.If(packet_requested): m.d.usb += [ # ... clear our transmit counter ... bytes_transmitted.eq(0), # ... latch in our response... latched_signal.eq(self.signal), ] # ... and start transmitting it. m.next = "TRANSMIT_RESPONSE" # TRANSMIT_RESPONSE -- we're now ready to send our latched response to the host. with m.State("TRANSMIT_RESPONSE"): is_last_byte = bytes_transmitted + 1 == bytes_in_signal # While we're transmitting, our Tx data is valid. m.d.comb += [ tx.valid.eq(1), tx.first.eq(bytes_transmitted == 0), tx.last.eq(is_last_byte) ] # Each time we receive a byte, move on to the next one. with m.If(tx.ready): m.d.usb += bytes_transmitted.eq(bytes_transmitted + 1) # If this is the last byte to be transmitted, move to waiting for an ACK. with m.If(is_last_byte): m.next = "WAIT_FOR_ACK" # WAIT_FOR_ACK -- we've now transmitted our full packet; we need to wait for the host to ACK it with m.State("WAIT_FOR_ACK"): # If the host does ACK, we're done! Move back to our idle state. with m.If(self.interface.handshakes_in.ack): m.d.comb += self.status_read_complete.eq(1) m.d.usb += self.interface.tx_pid_toggle[0].eq( ~self.interface.tx_pid_toggle[0]) m.next = "IDLE" # If the host starts a new packet without ACK'ing, we'll need to retransmit. # Wait for a new IN token. with m.If(self.interface.tokenizer.new_token): m.next = "RETRANSMIT" # RETRANSMIT -- the host failed to ACK the data we've most recently sent. # Wait here for the host to request the data again. with m.State("RETRANSMIT"): # Once the host does request the data again... with m.If(packet_requested): # ... retransmit it, starting from the beginning. m.d.usb += bytes_transmitted.eq(0), m.next = "TRANSMIT_RESPONSE" return m
def elaborate(self, platform): m = Module() m.submodules.rdiv = self.r_rdiv m.submodules.gdiv = self.r_gdiv m.submodules.bdiv = self.r_bdiv with m.FSM() as fsm: with m.State("START"): # Reset output signals m.d.sync += [ self.o_valid.eq(0), self.o_last.eq(0) ] # Transpose the coordinates so we're always in the positive X and Y quadrant. dx = Signal((self.width + 1, True)) dy = Signal((self.width + 1, True)) m.d.comb += [ dx.eq(self.i_x0 - self.i_x1), dy.eq(self.i_y0 - self.i_y1) ] m.d.sync += [ self.r_x0.eq(self.i_x0), self.r_y0.eq(self.i_y0), self.r_x1.eq(self.i_x1), self.r_y1.eq(self.i_y1), self.r_dx.eq(Mux(dx < 0, -dx, dx)), self.r_dy.eq(Mux(dy < 0, -dy, dy)) ] m.d.sync += [ self.r_red.eq(self.i_r0 << 4), self.r_green.eq(self.i_g0 << 4), self.r_blue.eq(self.i_b0 << 4), self.r_rdiv.i_colour.eq((self.i_r1 - self.i_r0) << 4), self.r_gdiv.i_colour.eq((self.i_g1 - self.i_g0) << 4), self.r_bdiv.i_colour.eq((self.i_b1 - self.i_b0) << 4), ] with m.If(self.i_start): m.next = "TRANSPOSE" with m.State("TRANSPOSE"): # Transpose if the angle is steep. steep = Signal() m.d.comb += steep.eq(self.r_dx < self.r_dy), m.d.sync += [ self.r_steep.eq(steep), self.r_x0.eq(Mux(steep, self.r_y0, self.r_x0)), self.r_y0.eq(Mux(steep, self.r_x0, self.r_y0)), self.r_x1.eq(Mux(steep, self.r_y1, self.r_x1)), self.r_y1.eq(Mux(steep, self.r_x1, self.r_y1)), self.r_dx.eq(Mux(steep, self.r_dy, self.r_dx)), self.r_dy.eq(Mux(steep, self.r_dx, self.r_dy)) ] m.d.sync += [ self.r_rdiv.i_start.eq(1), self.r_gdiv.i_start.eq(1), self.r_bdiv.i_start.eq(1), self.r_rdiv.i_dx.eq(self.r_dx), self.r_gdiv.i_dx.eq(self.r_dx), self.r_bdiv.i_dx.eq(self.r_dx) ] m.next = "FLIP" with m.State("FLIP"): # (x0, y0) should be the bottom left coordinate. flip = Signal() m.d.comb += flip.eq(self.r_x1 < self.r_x0) m.d.sync += [ self.r_error.eq(0), self.r_y_inc.eq(Mux(flip ^ (self.r_y0 < self.r_y1), +self.one, -self.one)) ] m.d.sync += [ self.r_x0.eq(Mux(flip, self.r_x1, self.r_x0)), self.r_y0.eq(Mux(flip, self.r_y1, self.r_y0)), self.r_x1.eq(Mux(flip, self.r_x0, self.r_x1)), self.r_y1.eq(Mux(flip, self.r_y0, self.r_y1)) ] m.next = "NEXT-PIXEL" with m.State("NEXT-PIXEL"): # Output current coordinates m.d.sync += [ self.o_x.eq(Mux(self.r_steep, self.r_y0, self.r_x0) >> 4), self.o_y.eq(Mux(self.r_steep, self.r_x0, self.r_y0) >> 4), self.o_r.eq(self.r_red >> 4), self.o_g.eq(self.r_green >> 4), self.o_b.eq(self.r_blue >> 4), self.o_valid.eq(1), self.o_last.eq(self.r_x0 > self.r_x1) ] # Calculate next coordinates m.d.sync += [ self.r_error.eq(self.r_error + (self.r_dy << 1)), self.r_x0.eq(self.r_x0 + self.one), self.r_red.eq(self.r_red + self.r_rdiv.o_result), self.r_green.eq(self.r_green + self.r_gdiv.o_result), self.r_blue.eq(self.r_blue + self.r_bdiv.o_result) ] with m.If(self.o_last): m.next = "FINISH" with m.Else(): m.next = "WAIT" # Wait for pixel acknowledgement before continuing. # While waiting, pre-calculate the next coordinates. with m.State("WAIT"): # If error goes above threshold, update Y with m.If(self.r_error > self.r_dx): m.d.sync += [ self.r_y0.eq(self.r_y0 + self.r_y_inc), self.r_error.eq(self.r_error - (self.r_dx << 1)) ] with m.If(self.i_next): m.next = "NEXT-PIXEL" # Wait for pixel acknowledgement before resetting. with m.State("FINISH"): m.d.sync += [ self.r_rdiv.i_reset.eq(1), self.r_gdiv.i_reset.eq(1), self.r_bdiv.i_reset.eq(1) ] with m.If(self.i_next): m.next = "START" return m
def elaborate(self, platform): m = Module() with m.FSM() as fsm: with m.State("START"): m.d.sync += self.o_ready.eq(0) m.d.sync += self.r_colour.eq(self.i_colour << 4) # The following mess calculates the reciprocal of i_dx # as a Q12.4 fixed-point number. m.d.sync += self.r_recip.eq(0) with m.If((self.i_dx >= 0) & (self.i_dx < 1)): m.d.sync += self.r_recip.eq(0) with m.If((self.i_dx >= 1) & (self.i_dx < 2)): m.d.sync += self.r_recip.eq(4096) with m.If((self.i_dx >= 2) & (self.i_dx < 3)): m.d.sync += self.r_recip.eq(2048) with m.If((self.i_dx >= 3) & (self.i_dx < 4)): m.d.sync += self.r_recip.eq(1365) with m.If((self.i_dx >= 4) & (self.i_dx < 5)): m.d.sync += self.r_recip.eq(1024) with m.If((self.i_dx >= 5) & (self.i_dx < 6)): m.d.sync += self.r_recip.eq(819) with m.If((self.i_dx >= 6) & (self.i_dx < 7)): m.d.sync += self.r_recip.eq(682) with m.If((self.i_dx >= 7) & (self.i_dx < 8)): m.d.sync += self.r_recip.eq(585) with m.If((self.i_dx >= 8) & (self.i_dx < 9)): m.d.sync += self.r_recip.eq(512) with m.If((self.i_dx >= 9) & (self.i_dx < 10)): m.d.sync += self.r_recip.eq(455) with m.If((self.i_dx >= 10) & (self.i_dx < 11)): m.d.sync += self.r_recip.eq(409) with m.If((self.i_dx >= 11) & (self.i_dx < 12)): m.d.sync += self.r_recip.eq(372) with m.If((self.i_dx >= 12) & (self.i_dx < 13)): m.d.sync += self.r_recip.eq(341) with m.If((self.i_dx >= 13) & (self.i_dx < 14)): m.d.sync += self.r_recip.eq(315) with m.If((self.i_dx >= 14) & (self.i_dx < 15)): m.d.sync += self.r_recip.eq(292) with m.If((self.i_dx >= 15) & (self.i_dx < 16)): m.d.sync += self.r_recip.eq(273) with m.If((self.i_dx >= 16) & (self.i_dx < 17)): m.d.sync += self.r_recip.eq(256) with m.If((self.i_dx >= 17) & (self.i_dx < 18)): m.d.sync += self.r_recip.eq(240) with m.If((self.i_dx >= 18) & (self.i_dx < 19)): m.d.sync += self.r_recip.eq(227) with m.If((self.i_dx >= 19) & (self.i_dx < 20)): m.d.sync += self.r_recip.eq(215) with m.If((self.i_dx >= 20) & (self.i_dx < 21)): m.d.sync += self.r_recip.eq(204) with m.If((self.i_dx >= 21) & (self.i_dx < 22)): m.d.sync += self.r_recip.eq(195) with m.If((self.i_dx >= 22) & (self.i_dx < 23)): m.d.sync += self.r_recip.eq(186) with m.If((self.i_dx >= 23) & (self.i_dx < 24)): m.d.sync += self.r_recip.eq(178) with m.If((self.i_dx >= 24) & (self.i_dx < 25)): m.d.sync += self.r_recip.eq(170) with m.If((self.i_dx >= 25) & (self.i_dx < 26)): m.d.sync += self.r_recip.eq(163) with m.If((self.i_dx >= 26) & (self.i_dx < 27)): m.d.sync += self.r_recip.eq(157) with m.If((self.i_dx >= 27) & (self.i_dx < 28)): m.d.sync += self.r_recip.eq(151) with m.If((self.i_dx >= 28) & (self.i_dx < 29)): m.d.sync += self.r_recip.eq(146) with m.If((self.i_dx >= 29) & (self.i_dx < 30)): m.d.sync += self.r_recip.eq(141) with m.If((self.i_dx >= 30) & (self.i_dx < 31)): m.d.sync += self.r_recip.eq(136) with m.If((self.i_dx >= 31) & (self.i_dx < 32)): m.d.sync += self.r_recip.eq(132) with m.If((self.i_dx >= 32) & (self.i_dx < 33)): m.d.sync += self.r_recip.eq(128) with m.If((self.i_dx >= 33) & (self.i_dx < 34)): m.d.sync += self.r_recip.eq(124) with m.If((self.i_dx >= 34) & (self.i_dx < 35)): m.d.sync += self.r_recip.eq(120) with m.If((self.i_dx >= 35) & (self.i_dx < 36)): m.d.sync += self.r_recip.eq(117) with m.If((self.i_dx >= 36) & (self.i_dx < 37)): m.d.sync += self.r_recip.eq(113) with m.If((self.i_dx >= 37) & (self.i_dx < 38)): m.d.sync += self.r_recip.eq(110) with m.If((self.i_dx >= 38) & (self.i_dx < 39)): m.d.sync += self.r_recip.eq(107) with m.If((self.i_dx >= 39) & (self.i_dx < 40)): m.d.sync += self.r_recip.eq(105) with m.If((self.i_dx >= 40) & (self.i_dx < 41)): m.d.sync += self.r_recip.eq(102) with m.If((self.i_dx >= 41) & (self.i_dx < 42)): m.d.sync += self.r_recip.eq(99) with m.If((self.i_dx >= 42) & (self.i_dx < 43)): m.d.sync += self.r_recip.eq(97) with m.If((self.i_dx >= 43) & (self.i_dx < 44)): m.d.sync += self.r_recip.eq(95) with m.If((self.i_dx >= 44) & (self.i_dx < 45)): m.d.sync += self.r_recip.eq(93) with m.If((self.i_dx >= 45) & (self.i_dx < 46)): m.d.sync += self.r_recip.eq(91) with m.If((self.i_dx >= 46) & (self.i_dx < 47)): m.d.sync += self.r_recip.eq(89) with m.If((self.i_dx >= 47) & (self.i_dx < 48)): m.d.sync += self.r_recip.eq(87) with m.If((self.i_dx >= 48) & (self.i_dx < 49)): m.d.sync += self.r_recip.eq(85) with m.If((self.i_dx >= 49) & (self.i_dx < 50)): m.d.sync += self.r_recip.eq(83) with m.If((self.i_dx >= 50) & (self.i_dx < 51)): m.d.sync += self.r_recip.eq(81) with m.If((self.i_dx >= 51) & (self.i_dx < 52)): m.d.sync += self.r_recip.eq(80) with m.If((self.i_dx >= 52) & (self.i_dx < 53)): m.d.sync += self.r_recip.eq(78) with m.If((self.i_dx >= 53) & (self.i_dx < 54)): m.d.sync += self.r_recip.eq(77) with m.If((self.i_dx >= 54) & (self.i_dx < 55)): m.d.sync += self.r_recip.eq(75) with m.If((self.i_dx >= 55) & (self.i_dx < 56)): m.d.sync += self.r_recip.eq(74) with m.If((self.i_dx >= 56) & (self.i_dx < 57)): m.d.sync += self.r_recip.eq(73) with m.If((self.i_dx >= 57) & (self.i_dx < 58)): m.d.sync += self.r_recip.eq(71) with m.If((self.i_dx >= 58) & (self.i_dx < 59)): m.d.sync += self.r_recip.eq(70) with m.If((self.i_dx >= 59) & (self.i_dx < 60)): m.d.sync += self.r_recip.eq(69) with m.If((self.i_dx >= 60) & (self.i_dx < 61)): m.d.sync += self.r_recip.eq(68) with m.If((self.i_dx >= 61) & (self.i_dx < 62)): m.d.sync += self.r_recip.eq(67) with m.If((self.i_dx >= 62) & (self.i_dx < 63)): m.d.sync += self.r_recip.eq(66) with m.If((self.i_dx >= 63) & (self.i_dx < 64)): m.d.sync += self.r_recip.eq(65) with m.If((self.i_dx >= 64) & (self.i_dx < 65)): m.d.sync += self.r_recip.eq(64) with m.If((self.i_dx >= 65) & (self.i_dx < 66)): m.d.sync += self.r_recip.eq(63) with m.If((self.i_dx >= 66) & (self.i_dx < 67)): m.d.sync += self.r_recip.eq(62) with m.If((self.i_dx >= 67) & (self.i_dx < 68)): m.d.sync += self.r_recip.eq(61) with m.If((self.i_dx >= 68) & (self.i_dx < 69)): m.d.sync += self.r_recip.eq(60) with m.If((self.i_dx >= 69) & (self.i_dx < 70)): m.d.sync += self.r_recip.eq(59) with m.If((self.i_dx >= 70) & (self.i_dx < 71)): m.d.sync += self.r_recip.eq(58) with m.If((self.i_dx >= 71) & (self.i_dx < 72)): m.d.sync += self.r_recip.eq(57) with m.If((self.i_dx >= 72) & (self.i_dx < 74)): m.d.sync += self.r_recip.eq(56) with m.If((self.i_dx >= 74) & (self.i_dx < 75)): m.d.sync += self.r_recip.eq(55) with m.If((self.i_dx >= 75) & (self.i_dx < 76)): m.d.sync += self.r_recip.eq(54) with m.If((self.i_dx >= 76) & (self.i_dx < 78)): m.d.sync += self.r_recip.eq(53) with m.If((self.i_dx >= 78) & (self.i_dx < 79)): m.d.sync += self.r_recip.eq(52) with m.If((self.i_dx >= 79) & (self.i_dx < 81)): m.d.sync += self.r_recip.eq(51) with m.If((self.i_dx >= 81) & (self.i_dx < 82)): m.d.sync += self.r_recip.eq(50) with m.If((self.i_dx >= 82) & (self.i_dx < 84)): m.d.sync += self.r_recip.eq(49) with m.If((self.i_dx >= 84) & (self.i_dx < 86)): m.d.sync += self.r_recip.eq(48) with m.If((self.i_dx >= 86) & (self.i_dx < 88)): m.d.sync += self.r_recip.eq(47) with m.If((self.i_dx >= 88) & (self.i_dx < 90)): m.d.sync += self.r_recip.eq(46) with m.If((self.i_dx >= 90) & (self.i_dx < 92)): m.d.sync += self.r_recip.eq(45) with m.If((self.i_dx >= 92) & (self.i_dx < 94)): m.d.sync += self.r_recip.eq(44) with m.If((self.i_dx >= 94) & (self.i_dx < 96)): m.d.sync += self.r_recip.eq(43) with m.If((self.i_dx >= 96) & (self.i_dx < 98)): m.d.sync += self.r_recip.eq(42) with m.If((self.i_dx >= 98) & (self.i_dx < 100)): m.d.sync += self.r_recip.eq(41) with m.If((self.i_dx >= 100) & (self.i_dx < 103)): m.d.sync += self.r_recip.eq(40) with m.If((self.i_dx >= 103) & (self.i_dx < 106)): m.d.sync += self.r_recip.eq(39) with m.If((self.i_dx >= 106) & (self.i_dx < 108)): m.d.sync += self.r_recip.eq(38) with m.If((self.i_dx >= 108) & (self.i_dx < 111)): m.d.sync += self.r_recip.eq(37) with m.If((self.i_dx >= 111) & (self.i_dx < 114)): m.d.sync += self.r_recip.eq(36) with m.If((self.i_dx >= 114) & (self.i_dx < 118)): m.d.sync += self.r_recip.eq(35) with m.If((self.i_dx >= 118) & (self.i_dx < 121)): m.d.sync += self.r_recip.eq(34) with m.If((self.i_dx >= 121) & (self.i_dx < 125)): m.d.sync += self.r_recip.eq(33) with m.If((self.i_dx >= 125) & (self.i_dx < 129)): m.d.sync += self.r_recip.eq(32) with m.If((self.i_dx >= 129) & (self.i_dx < 133)): m.d.sync += self.r_recip.eq(31) with m.If((self.i_dx >= 133) & (self.i_dx < 137)): m.d.sync += self.r_recip.eq(30) with m.If((self.i_dx >= 137) & (self.i_dx < 142)): m.d.sync += self.r_recip.eq(29) with m.If((self.i_dx >= 142) & (self.i_dx < 147)): m.d.sync += self.r_recip.eq(28) with m.If((self.i_dx >= 147) & (self.i_dx < 152)): m.d.sync += self.r_recip.eq(27) with m.If((self.i_dx >= 152) & (self.i_dx < 158)): m.d.sync += self.r_recip.eq(26) with m.If((self.i_dx >= 158) & (self.i_dx < 164)): m.d.sync += self.r_recip.eq(25) with m.If((self.i_dx >= 164) & (self.i_dx < 171)): m.d.sync += self.r_recip.eq(24) with m.If((self.i_dx >= 171) & (self.i_dx < 179)): m.d.sync += self.r_recip.eq(23) with m.If((self.i_dx >= 179) & (self.i_dx < 187)): m.d.sync += self.r_recip.eq(22) with m.If((self.i_dx >= 187) & (self.i_dx < 196)): m.d.sync += self.r_recip.eq(21) with m.If((self.i_dx >= 196) & (self.i_dx < 205)): m.d.sync += self.r_recip.eq(20) with m.If((self.i_dx >= 205) & (self.i_dx < 216)): m.d.sync += self.r_recip.eq(19) with m.If((self.i_dx >= 216) & (self.i_dx < 228)): m.d.sync += self.r_recip.eq(18) with m.If((self.i_dx >= 228) & (self.i_dx < 241)): m.d.sync += self.r_recip.eq(17) with m.If((self.i_dx >= 241) & (self.i_dx < 257)): m.d.sync += self.r_recip.eq(16) with m.If((self.i_dx >= 257) & (self.i_dx < 274)): m.d.sync += self.r_recip.eq(15) with m.If((self.i_dx >= 274) & (self.i_dx < 293)): m.d.sync += self.r_recip.eq(14) with m.If((self.i_dx >= 293) & (self.i_dx < 316)): m.d.sync += self.r_recip.eq(13) with m.If((self.i_dx >= 316) & (self.i_dx < 342)): m.d.sync += self.r_recip.eq(12) with m.If((self.i_dx >= 342) & (self.i_dx < 373)): m.d.sync += self.r_recip.eq(11) with m.If((self.i_dx >= 373) & (self.i_dx < 410)): m.d.sync += self.r_recip.eq(10) with m.If((self.i_dx >= 410) & (self.i_dx < 456)): m.d.sync += self.r_recip.eq(9) with m.If((self.i_dx >= 456) & (self.i_dx < 513)): m.d.sync += self.r_recip.eq(8) with m.If((self.i_dx >= 513) & (self.i_dx < 586)): m.d.sync += self.r_recip.eq(7) with m.If((self.i_dx >= 586) & (self.i_dx < 683)): m.d.sync += self.r_recip.eq(6) with m.If((self.i_dx >= 683) & (self.i_dx < 820)): m.d.sync += self.r_recip.eq(5) with m.If((self.i_dx >= 820) & (self.i_dx < 1025)): m.d.sync += self.r_recip.eq(4) with m.If((self.i_dx >= 1025) & (self.i_dx < 1366)): m.d.sync += self.r_recip.eq(3) with m.If((self.i_dx >= 1366) & (self.i_dx < 2049)): m.d.sync += self.r_recip.eq(2) with m.If((self.i_dx >= 2049) & (self.i_dx < 4097)): m.d.sync += self.r_recip.eq(1) with m.If(self.i_start): m.next = "RECIP" with m.State("RECIP"): m.d.sync += self.o_ready.eq(1) m.d.sync += self.o_result.eq(self.r_colour * self.r_recip) with m.State("DONE"): with m.If(self.i_reset): m.next = "START" return m
def elaborate(self, platform): m = Module() # Create MDIO submodule clk_div = int(self.clk_freq // 2.5e6) m.submodules.mdio = mdio = MDIO(clk_div, self.mdio, self.mdc) self.mdio_mod = mdio mdio.phy_addr = Const(self.phy_addr) # Latches for registers we read bsr = Signal(16) # Compute output signal from registers m.d.comb += self.link_up.eq(bsr[2] & # Link must be up ~bsr[4] & # No remote fault bsr[5] & # Autonegotiation complete bsr[14] # 100Mbps full duplex ) registers_to_write = [ # Enable 100Mbps, autonegotiation, and full-duplex # ("BCR", 0x00, (1 << 13) | (1 << 12) | (1 << 8)), ] registers_to_read = [ # Basic status register contains everything we need to know ("BSR", 0x01, bsr), ] # Controller FSM one_ms = int(self.clk_freq // 1000) counter = Signal(max=one_ms) with m.FSM(): # Assert PHY_RST and begin 1ms counter with m.State("RESET"): m.d.comb += self.phy_rst.eq(0) m.d.sync += counter.eq(one_ms) m.next = "RESET_WAIT" # Wait for reset timeout with m.State("RESET_WAIT"): m.d.comb += self.phy_rst.eq(0) m.d.sync += counter.eq(counter - 1) with m.If(self.phy_reset): m.next = "RESET" with m.Elif(counter == 0): m.d.sync += counter.eq(one_ms) write = bool(registers_to_write) m.next = "WRITE_WAIT" if write else "POLL_WAIT" # Wait 1ms before writing if registers_to_write: with m.State("WRITE_WAIT"): m.d.comb += self.phy_rst.eq(1), m.d.sync += counter.eq(counter - 1) with m.If(self.phy_reset): m.next = "RESET" with m.Elif(counter == 0): m.next = f"WRITE_{registers_to_write[0][0]}" else: m.d.comb += mdio.write_data.eq(0) for idx, (name, addr, val) in enumerate(registers_to_write): if idx == len(registers_to_write) - 1: next_state = "POLL_WAIT" else: next_state = f"WRITE_{registers_to_write[idx+1][0]}" with m.State(f"WRITE_{name}"): m.d.comb += [ self.phy_rst.eq(0), mdio.reg_addr.eq(Const(addr)), mdio.rw.eq(1), mdio.write_data.eq(Const(val)), mdio.start.eq(1), ] with m.If(self.phy_reset): m.next = "RESET" with m.Elif(mdio.busy): m.next = f"WRITE_{name}_WAIT" with m.State(f"WRITE_{name}_WAIT"): m.d.comb += [ self.phy_rst.eq(1), mdio.reg_addr.eq(0), mdio.rw.eq(0), mdio.write_data.eq(0), mdio.start.eq(0), ] with m.If(self.phy_reset): m.next = "RESET" with m.Elif(~mdio.busy): m.d.sync += counter.eq(one_ms) m.next = next_state # Wait 1ms between polls with m.State("POLL_WAIT"): m.d.comb += self.phy_rst.eq(1) m.d.sync += counter.eq(counter - 1) with m.If(self.phy_reset): m.next = "RESET" with m.Elif(counter == 0): m.next = f"POLL_{registers_to_read[0][0]}" for idx, (name, addr, latch) in enumerate(registers_to_read): if idx == len(registers_to_read) - 1: next_state = "POLL_WAIT" else: next_state = f"POLL_{registers_to_read[idx+1][0]}" # Trigger a read of the register with m.State(f"POLL_{name}"): m.d.comb += [ self.phy_rst.eq(1), mdio.reg_addr.eq(Const(addr)), mdio.rw.eq(0), mdio.start.eq(1), ] with m.If(self.phy_reset): m.next = "RESET" with m.Elif(mdio.busy): m.next = f"POLL_{name}_WAIT" # Wait for MDIO to stop being busy with m.State(f"POLL_{name}_WAIT"): m.d.comb += [ self.phy_rst.eq(1), mdio.reg_addr.eq(0), mdio.rw.eq(0), mdio.start.eq(0), ] with m.If(self.phy_reset): m.next = "RESET" with m.Elif(~mdio.busy): m.d.sync += [ latch.eq(mdio.read_data), counter.eq(one_ms), ] m.next = next_state return m
def elaborate(self, platform): m = Module() # # Transciever state. # # Handle our PID-sequence reset. # Note that we store the _inverse_ of our data PID, as we'll toggle our DATA PID # before sending. with m.If(self.reset_sequence): m.d.usb += self.data_pid.eq(~self.start_with_data1) # # Transmit buffer. # # Our USB connection imposed a few requirements on our stream: # 1) we must be able to transmit packets at a full rate; i.e. # must be asserted from the start to the end of our transfer; and # 2) we must be able to re-transmit data if a given packet is not ACK'd. # # Accordingly, we'll buffer a full USB packet of data, and then transmit # it once either a) our buffer is full, or 2) the transfer ends (last=1). # # This implementation is double buffered; so a buffer fill can be pipelined # with a transmit. # # We'll create two buffers; so we can fill one as we empty the other. # Since each buffer will be used for every other transaction, and our PID toggle flips every other transcation, # we'll identify which buffer we're targeting by the current PID toggle. buffer = Array( Memory(width=8, depth=self._max_packet_size, name=f"transmit_buffer_{i}") for i in range(2)) buffer_write_ports = Array(buffer[i].write_port(domain="usb") for i in range(2)) buffer_read_ports = Array(buffer[i].read_port(domain="usb") for i in range(2)) m.submodules.read_port_0, m.submodules.read_port_1 = buffer_read_ports m.submodules.write_port_0, m.submodules.write_port_1 = buffer_write_ports # Create values equivalent to the buffer numbers for our read and write buffer; which switch # whenever we swap our two buffers. write_buffer_number = self.data_pid[0] read_buffer_number = ~self.data_pid[0] # Create a shorthand that refers to the buffer to be filled; and the buffer to send from. # We'll call these the Read and Write buffers. buffer_write = buffer_write_ports[write_buffer_number] buffer_read = buffer_read_ports[read_buffer_number] # Buffer state tracking: # - Our ``fill_count`` keeps track of how much data is stored in a given buffer. # - Our ``stream_ended`` bit keeps track of whether the stream ended while filling up # the given buffer. This indicates that the buffer cannot be filled further; and, when # ``generate_zlps`` is enabled, is used to determine if the given buffer should end in # a short packet; which determines whether ZLPs are emitted. buffer_fill_count = Array( Signal(range(0, self._max_packet_size + 1)) for _ in range(2)) buffer_stream_ended = Array( Signal(name=f"stream_ended_in_buffer{i}") for i in range(2)) # Create shortcuts to active fill_count / stream_ended signals for the buffer being written. write_fill_count = buffer_fill_count[write_buffer_number] write_stream_ended = buffer_stream_ended[write_buffer_number] # Create shortcuts to the fill_count / stream_ended signals for the packet being sent. read_fill_count = buffer_fill_count[read_buffer_number] read_stream_ended = buffer_stream_ended[read_buffer_number] # Keep track of our current send position; which determines where we are in the packet. send_position = Signal(range(0, self._max_packet_size + 1)) # Shortcut names. in_stream = self.transfer_stream out_stream = self.packet_stream # Use our memory's two ports to capture data from our transfer stream; and two emit packets # into our packet stream. Since we'll never receive to anywhere else, or transmit to anywhere else, # we can just unconditionally connect these. m.d.comb += [ # We'll only ever -write- data from our input stream... buffer_write_ports[0].data.eq(in_stream.payload), buffer_write_ports[0].addr.eq(write_fill_count), buffer_write_ports[1].data.eq(in_stream.payload), buffer_write_ports[1].addr.eq(write_fill_count), # ... and we'll only ever -send- data from the Read buffer. buffer_read.addr.eq(send_position), out_stream.payload.eq(buffer_read.data), # We're ready to receive data iff we have space in the buffer we're currently filling. in_stream.ready.eq((write_fill_count != self._max_packet_size) & ~write_stream_ended), buffer_write.en.eq(in_stream.valid & in_stream.ready) ] # Increment our fill count whenever we accept new data. with m.If(buffer_write.en): m.d.usb += write_fill_count.eq(write_fill_count + 1) # If the stream ends while we're adding data to the buffer, mark this as an ended stream. with m.If(in_stream.last & buffer_write.en): m.d.usb += write_stream_ended.eq(1) # Shortcut for when we need to deal with an in token. # Pulses high an interpacket delay after receiving an IN token. in_token_received = self.active & self.tokenizer.is_in & self.tokenizer.ready_for_response with m.FSM(domain='usb'): # WAIT_FOR_DATA -- We don't yet have a full packet to transmit, so we'll capture data # to fill the our buffer. At full throughput, this state will never be reached after # the initial post-reset fill. with m.State("WAIT_FOR_DATA"): # We can't yet send data; so NAK any packet requests. m.d.comb += self.handshakes_out.nak.eq(in_token_received) # If we have valid data that will end our packet, we're no longer waiting for data. # We'll now wait for the host to request data from us. packet_complete = (write_fill_count + 1 == self._max_packet_size) will_end_packet = packet_complete | in_stream.last with m.If(in_stream.valid & will_end_packet): # If we've just finished a packet, we now have data we can send! with m.If(packet_complete | in_stream.last): m.next = "WAIT_TO_SEND" m.d.usb += [ # We're now ready to take the data we've captured and _transmit_ it. # We'll swap our read and write buffers, and toggle our data PID. self.data_pid[0].eq(~self.data_pid[0]), # Mark our current stream as no longer having ended. read_stream_ended.eq(0) ] # WAIT_TO_SEND -- we now have at least a buffer full of data to send; we'll # need to wait for an IN token to send it. with m.State("WAIT_TO_SEND"): m.d.usb += send_position.eq(0), # Once we get an IN token, move to sending a packet. with m.If(in_token_received): # If we have a packet to send, send it. with m.If(read_fill_count): m.next = "SEND_PACKET" m.d.usb += out_stream.first.eq(1) # Otherwise, we entered a transmit path without any data in the buffer. with m.Else(): m.d.comb += [ # Send a ZLP... out_stream.valid.eq(1), out_stream.last.eq(1), ] # ... and clear the need to follow up with one, since we've just sent a short packet. m.d.usb += read_stream_ended.eq(0) m.next = "WAIT_FOR_ACK" with m.State("SEND_PACKET"): last_packet = (send_position + 1 == read_fill_count) m.d.comb += [ # We're always going to be sending valid data, since data is always # available from our memory. out_stream.valid.eq(1), # Let our transmitter know when we've reached our last packet. out_stream.last.eq(last_packet) ] # Once our transmitter accepts our data... with m.If(out_stream.ready): m.d.usb += [ # ... move to the next byte in our packet ... send_position.eq(send_position + 1), # ... and mark our packet as no longer the first. out_stream.first.eq(0) ] # Move our memory pointer to its next position. m.d.comb += buffer_read.addr.eq(send_position + 1), # If we've just sent our last packet, we're now ready to wait for a # response from our host. with m.If(last_packet): m.next = 'WAIT_FOR_ACK' # WAIT_FOR_ACK -- We've just sent a packet; but don't know if the host has # received it correctly. We'll wait to see if the host ACKs. with m.State("WAIT_FOR_ACK"): # If the host does ACK... with m.If(self.handshakes_in.ack): # ... clear the data we've sent from our buffer. m.d.usb += read_fill_count.eq(0) # Figure out if we'll need to follow up with a ZLP. If we have ZLP generation enabled, # we'll make sure we end on a short packet. If this is max-packet-size packet _and_ our # transfer ended with this packet; we'll need to inject a ZLP. follow_up_with_zlp = \ self.generate_zlps & (read_fill_count == self._max_packet_size) & read_stream_ended # If we're following up with a ZLP, move back to our "wait to send" state. # Since we've now cleared our fill count; this next go-around will emit a ZLP. with m.If(follow_up_with_zlp): m.next = "WAIT_TO_SEND" # Otherwise, there's a possibility we already have a packet-worth of data waiting # for us in our "write buffer", which we've been filling in the background. # If this is the case, we'll flip which buffer we're working with, toggle our data pid, # and then ready ourselves for transmit. packet_completing = in_stream.valid & ( write_fill_count + 1 == self._max_packet_size) with m.Elif(~in_stream.ready | packet_completing): m.next = "WAIT_TO_SEND" m.d.usb += [ self.data_pid[0].eq(~self.data_pid[0]), read_stream_ended.eq(0) ] # If neither of the above conditions are true; we now don't have enough data to send. # We'll wait for enough data to transmit. with m.Else(): m.next = "WAIT_FOR_DATA" # If the host starts a new packet without ACK'ing, we'll need to retransmit. # We'll move back to our "wait for token" state without clearing our buffer. with m.If(self.tokenizer.new_token): m.next = 'WAIT_TO_SEND' return m
def elaborate(self, platform): m = Module() # # Core ROM. # data_length = len(self.data) rom = Memory(width=self.data_width, depth=data_length, init=self.data) m.submodules.rom_read_port = rom_read_port = rom.read_port() # Register that stores our current position in the stream. position_in_stream = Signal(range(0, data_length)) # Track when we're on the first and last packet. on_first_packet = position_in_stream == 0 on_last_packet = \ (position_in_stream == (data_length - 1)) | \ (position_in_stream == (self.max_length - 1)) m.d.comb += [ # Always drive the stream from our current memory output... self.stream.payload .eq(rom_read_port.data), ## ... and base First and Last based on our current position in the stream. self.stream.first .eq(on_first_packet & self.stream.valid), self.stream.last .eq(on_last_packet & self.stream.valid) ] # # Controller. # with m.FSM(domain=self.domain) as fsm: m.d.comb += self.stream.valid.eq(fsm.ongoing('STREAMING')) # IDLE -- we're not actively transmitting. with m.State('IDLE'): # Keep ourselves at the beginning of the stream, but don't yet count. m.d.sync += position_in_stream.eq(0) # Once the user requests that we start, move to our stream being valid. with m.If(self.start & (self.max_length > 0)): m.next = 'STREAMING' # STREAMING -- we're actively transmitting data with m.State('STREAMING'): m.d.comb += [ rom_read_port.addr .eq(position_in_stream) ] # If the current data byte is accepted, move past it. with m.If(self.stream.ready): should_continue = \ ((position_in_stream + 1) < self.max_length) & \ ((position_in_stream + 1) < data_length) # If there's still data left to transmit, move forward. with m.If(should_continue): m.d.sync += position_in_stream.eq(position_in_stream + 1) m.d.comb += rom_read_port.addr.eq(position_in_stream + 1) # Otherwise, we've finished streaming. Return to IDLE. with m.Else(): m.next = 'DONE' # DONE -- report our completion; and then return to idle with m.State('DONE'): m.d.comb += self.done.eq(1) m.next = 'IDLE' # Convert our sync domain to the domain requested by the user, if necessary. if self.domain != "sync": m = DomainRenamer({"sync": self.domain})(m) return m
def elaborate(self, platform): m = Module() interface = self.interface # Create convenience aliases for our interface components. setup = interface.setup handshake_generator = interface.handshakes_out tx = interface.tx # # Submodules # # Handler for Get Descriptor requests; responds with our various fixed descriptors. m.submodules.get_descriptor = get_descriptor_handler = GetDescriptorHandler( self.descriptors) m.d.comb += [ get_descriptor_handler.value.eq(setup.value), get_descriptor_handler.length.eq(setup.length), ] # Handler for various small-constant-response requests (GET_CONFIGURATION, GET_STATUS). m.submodules.transmitter = transmitter = \ StreamSerializer(data_length=2, domain="usb", stream_type=USBInStreamInterface, max_length_width=2) # # Handlers. # with m.If(setup.type == USBRequestType.STANDARD): with m.FSM(domain="usb"): # IDLE -- not handling any active request with m.State('IDLE'): # If we've received a new setup packet, handle it. with m.If(setup.received): # Select which standard packet we're going to handler. with m.Switch(setup.request): with m.Case(USBStandardRequests.GET_STATUS): m.next = 'GET_STATUS' with m.Case(USBStandardRequests.SET_ADDRESS): m.next = 'SET_ADDRESS' with m.Case(USBStandardRequests.SET_CONFIGURATION): m.next = 'SET_CONFIGURATION' with m.Case(USBStandardRequests.GET_DESCRIPTOR): m.next = 'GET_DESCRIPTOR' with m.Case(USBStandardRequests.GET_CONFIGURATION): m.next = 'GET_CONFIGURATION' with m.Case(): m.next = 'UNHANDLED' # GET_STATUS -- Fetch the device's status. # For now, we'll always return '0'. with m.State('GET_STATUS'): # TODO: handle reporting endpoint stall status # TODO: copy the remote wakeup and bus-powered attributes from bmAttributes of the relevant descriptor? self.handle_simple_data_request(m, transmitter, 0, length=2) # SET_ADDRESS -- The host is trying to assign us an address. with m.State('SET_ADDRESS'): self.handle_register_write_request( m, interface.new_address, interface.address_changed) # SET_CONFIGURATION -- The host is trying to select an active configuration. with m.State('SET_CONFIGURATION'): # TODO: stall if we don't have a relevant configuration self.handle_register_write_request( m, interface.new_config, interface.config_changed) # GET_DESCRIPTOR -- The host is asking for a USB descriptor -- for us to "self describe". with m.State('GET_DESCRIPTOR'): m.d.comb += [ get_descriptor_handler.tx.attach(tx), handshake_generator.stall.eq( get_descriptor_handler.stall) ] # Respond to our data stage with a descriptor... with m.If(interface.data_requested): m.d.comb += get_descriptor_handler.start.eq(1), # ... and ACK our status stage. with m.If(interface.status_requested): m.d.comb += handshake_generator.ack.eq(1) m.next = 'IDLE' # GET_CONFIGURATION -- The host is asking for the active configuration number. with m.State('GET_CONFIGURATION'): self.handle_simple_data_request(m, transmitter, interface.active_config) # UNHANDLED -- we've received a request we're not prepared to handle with m.State('UNHANDLED'): # When we next have an opportunity to stall, do so, # and then return to idle. with m.If(interface.data_requested | interface.status_requested): m.d.comb += handshake_generator.stall.eq(1) m.next = 'IDLE' return m
def elaborate(self, platform): m = Module() # If we're standalone, generate the things we need. if self.standalone: # Create our tokenizer... m.submodules.tokenizer = tokenizer = USBTokenDetector( utmi=self.utmi) m.d.comb += tokenizer.interface.connect(self.tokenizer) # ... and our timer. m.submodules.timer = timer = USBInterpacketTimer() timer.add_interface(self.timer) m.d.comb += timer.speed.eq(self.speed) # Create a data-packet-deserializer, which we'll use to capture the # contents of the setup data packets. m.submodules.data_handler = data_handler = \ USBDataPacketDeserializer(utmi=self.utmi, max_packet_size=8, create_crc_generator=self.standalone) m.d.comb += self.data_crc.connect(data_handler.data_crc) # Instruct our interpacket timer to begin counting when we complete receiving # our setup packet. This will allow us to track interpacket delays. m.d.comb += self.timer.start.eq(data_handler.new_packet) # Keep our output signals de-asserted unless specified. m.d.usb += [ self.packet.received.eq(0), ] with m.FSM(domain="usb"): # IDLE -- we haven't yet detected a SETUP transaction directed at us with m.State('IDLE'): pid_matches = (self.tokenizer.pid == self.SETUP_PID) # If we're just received a new SETUP token addressed to us, # the next data packet is going to be for us. with m.If(pid_matches & self.tokenizer.new_token): m.next = 'READ_DATA' # READ_DATA -- we've just seen a SETUP token, and are waiting for the # data payload of the transaction, which contains the setup packet. with m.State('READ_DATA'): # If we receive a token packet before we receive a DATA packet, # this is a PID mismatch. Bail out and start over. with m.If(self.tokenizer.new_token): m.next = 'IDLE' # If we have a new packet, parse it as setup data. with m.If(data_handler.new_packet): # If we got exactly eight bytes, this is a valid setup packet. with m.If(data_handler.length == 8): # Collect the signals that make up our bmRequestType [USB2, 9.3]. request_type = Cat(self.packet.recipient, self.packet.type, self.packet.is_in_request) m.d.usb += [ # Parse the setup data itself... request_type.eq(data_handler.packet[0]), self.packet.request.eq(data_handler.packet[1]), self.packet.value.eq( Cat(data_handler.packet[2], data_handler.packet[3])), self.packet.index.eq( Cat(data_handler.packet[4], data_handler.packet[5])), self.packet.length.eq( Cat(data_handler.packet[6], data_handler.packet[7])), # ... and indicate that we have new data. self.packet.received.eq(1), ] # We'll now need to wait a receive-transmit delay before initiating our ACK. # Per the USB 2.0 and ULPI 1.1 specifications: # - A HS device needs to wait 8 HS bit periods before transmitting [USB2, 7.1.18.2]. # Each ULPI cycle is 8 HS bit periods, so we'll only need to wait one cycle. # - We'll use our interpacket delay timer for everything else. with m.If(self.timer.tx_allowed | (self.speed == USBSpeed.HIGH)): # If we're a high speed device, we only need to wait for a single ULPI cycle. # Processing delays mean we've already met our interpacket delay; and we can ACK # immediately. m.d.comb += self.ack.eq(1) m.next = "IDLE" # For other cases, handle the interpacket delay by waiting. with m.Else(): m.next = "INTERPACKET_DELAY" # Otherwise, this isn't; and we should ignore it. [USB2, 8.5.3] with m.Else(): m.next = "IDLE" # INTERPACKET -- wait for an inter-packet delay before responding with m.State('INTERPACKET_DELAY'): # ... and once it equals zero, ACK and return to idle. with m.If(self.timer.tx_allowed): m.d.comb += self.ack.eq(1) m.next = "IDLE" return m
def elaborate(self, platform): m = Module() spi = self.spi sample_edge = falling_edge_detector(m, spi.sck) # Bit counter: counts the number of bits received. max_bit_count = max(self.word_size, self.command_size) bit_count = Signal(range(0, max_bit_count + 1)) # Shift registers for our command and data. current_command = Signal.like(self.command) current_word = Signal.like(self.word_received) # De-assert our control signals unless explicitly asserted. m.d.sync += [ self.command_ready.eq(0), self.word_complete.eq(0) ] with m.FSM(): # STALL: entered when we can't accept new bits -- either when # CS starts asserted, or when we've received more data than expected. with m.State("STALL"): # Wait for CS to clear. with m.If(~spi.cs): m.next = 'IDLE' # We ignore all data until chip select is asserted, as that data Isn't For Us (TM). # We'll spin and do nothing until the bus-master addresses us. with m.State('IDLE'): m.d.sync += bit_count.eq(0) with m.If(spi.cs): m.next = 'RECEIVE_COMMAND' # Once CS is low, we'll shift in our command. with m.State('RECEIVE_COMMAND'): # Continue shifting in data until we have a full command. with m.If(bit_count < self.command_size): with m.If(sample_edge): m.d.sync += [ bit_count .eq(bit_count + 1), current_command .eq(Cat(spi.sdi, current_command[:-1])) ] # ... and then pass that command out to our controller. with m.Else(): m.d.sync += [ bit_count .eq(0), self.command_ready .eq(1), self.command .eq(current_command) ] m.next = 'PROCESSING' # Give our controller a wait state to prepare any response they might want to... with m.State('PROCESSING'): m.next = 'LATCH_OUTPUT' # ... and then latch in the response to transmit. with m.State('LATCH_OUTPUT'): m.d.sync += current_word.eq(self.word_to_send) m.next = 'SHIFT_DATA' # Finally, exchange data. with m.State('SHIFT_DATA'): m.d.sync += spi.sdo.eq(current_word[-1]) # Continue shifting data until we have a full word. with m.If(bit_count < self.word_size): with m.If(sample_edge): m.d.sync += [ bit_count .eq(bit_count + 1), current_word .eq(Cat(spi.sdi, current_word[:-1])) ] # ... and then output that word on our bus. with m.Else(): m.d.sync += [ bit_count .eq(0), self.word_complete .eq(1), self.word_received .eq(current_word) ] # Stay in the stall state until CS is de-asserted. m.next = 'STALL' return m
def elaborate(self, platform): m = Module() # Create our core, single-byte-wide endpoint, and attach it directly to our interface. m.submodules.stream_ep = stream_ep = USBStreamInEndpoint( endpoint_number=self._endpoint_number, max_packet_size=self._max_packet_size ) stream_ep.interface = self.interface # Create semantic aliases for byte-wise and word-wise streams; # so the code below reads more clearly. byte_stream = stream_ep.stream word_stream = self.stream # We'll put each word to be sent through an shift register # that shifts out words a byte at a time. data_shift = Signal.like(word_stream.payload) # Latched versions of our first and last signals. first_latched = Signal() last_latched = Signal() # Count how many bytes we have left to send. bytes_to_send = Signal(range(0, self._byte_width + 1)) # Always provide our inner transmitter with the least byte of our shift register. m.d.comb += byte_stream.payload.eq(data_shift[0:8]) with m.FSM(domain="usb"): # IDLE: transmitter is waiting for input with m.State("IDLE"): m.d.comb += word_stream.ready.eq(1) # Once we get a send request, fill in our shift register, and start shifting. with m.If(word_stream.valid): m.d.usb += [ data_shift .eq(word_stream.payload), first_latched .eq(word_stream.first), last_latched .eq(word_stream.last), bytes_to_send .eq(self._byte_width - 1), ] m.next = "TRANSMIT" # TRANSMIT: actively send each of the bytes of our word with m.State("TRANSMIT"): m.d.comb += byte_stream.valid.eq(1) # Once the byte-stream is accepting our input... with m.If(byte_stream.ready): is_first_byte = (bytes_to_send == self._byte_width - 1) is_last_byte = (bytes_to_send == 0) # Pass through our First and Last signals, but only on the first and # last bytes of our word, respectively. m.d.comb += [ byte_stream.first .eq(first_latched & is_first_byte), byte_stream.last .eq(last_latched & is_last_byte) ] # ... if we have bytes left to send, move to the next one. with m.If(bytes_to_send > 0): m.d.usb += [ bytes_to_send .eq(bytes_to_send - 1), data_shift .eq(data_shift[8:]), ] # Otherwise, complete the frame. with m.Else(): m.d.comb += word_stream.ready.eq(1) # If we still have data to send, move to the next byte... with m.If(self.stream.valid): m.d.usb += [ data_shift .eq(word_stream.payload), first_latched .eq(word_stream.first), last_latched .eq(word_stream.last), bytes_to_send .eq(self._byte_width - 1), ] # ... otherwise, move to our idle state. with m.Else(): m.next = "IDLE" return m