def elaborate(self, platform): m = Module() interface = self.interface setup = self.interface.setup # # Class request handlers. # with m.If(setup.type == USBRequestType.CLASS): with m.Switch(setup.request): # SET_LINE_CODING: The host attempts to tell us how it wants serial data # encoding. Since we output a stream, we'll ignore the actual line coding. with m.Case(self.SET_LINE_CODING): # Always ACK the data out... with m.If(interface.rx_ready_for_response): m.d.comb += interface.handshakes_out.ack.eq(1) # ... and accept whatever the request was. with m.If(interface.status_requested): m.d.comb += self.send_zlp() with m.Case(): # # Stall unhandled requests. # with m.If(interface.status_requested | interface.data_requested): m.d.comb += interface.handshakes_out.stall.eq(1) return m
def elaborate(self, platform): m = Module() with m.Switch(self.funct3): with m.Case(Funct3.OR): m.d.comb += self.res.eq(self.src1 | self.src2) with m.Case(Funct3.AND): m.d.comb += self.res.eq(self.src1 & self.src2) with m.Case(Funct3.XOR): m.d.comb += self.res.eq(self.src1 ^ self.src2) return m
def elaborate(self, platform): m = Module() interface = self.interface setup = self.interface.setup # Grab a reference to the board's LEDs. leds = Cat(platform.request_optional("led", i, default=NullPin()).o for i in range(8)) # # Vendor request handlers. with m.If(setup.type == USBRequestType.VENDOR): with m.Switch(setup.request): # SET_LEDS request handler: handler that sets the board's LEDS # to a user provided value with m.Case(self.REQUEST_SET_LEDS): # If we have an active data byte, splat it onto the LEDs. # # For simplicity of this example, we'll accept any byte in # the packet; and not just the first one; each byte will # cause an update. This is fun; we can PWM the LEDs with # USB packets. :) with m.If(interface.rx.valid & interface.rx.next): m.d.usb += leds.eq(interface.rx.payload) # Once the receive is complete, respond with an ACK. with m.If(interface.rx_ready_for_response): m.d.comb += interface.handshakes_out.ack.eq(1) # If we reach the status stage, send a ZLP. with m.If(interface.status_requested): m.d.comb += self.send_zlp() with m.Case(): # # Stall unhandled requests. # with m.If(interface.status_requested | interface.data_requested): m.d.comb += interface.handshakes_out.stall.eq(1) return m
def elaborate(self, platform): m = Module() comb = m.d.comb with m.Switch(self.funct3): with m.Case(Funct3.W): comb += self.mask.eq(0b1111) with m.Case(Funct3.H): comb += self.mask.eq(0b0011) with m.Case(Funct3.B): comb += self.mask.eq(0b0001) with m.Case(Funct3.HU): comb += self.mask.eq(0b0011) with m.Case(Funct3.BU): comb += self.mask.eq(0b0001) return m
def elaborate(self, platform): m = Module() # # Our module has three core parts: # - an encoder, which converts from our one-hot signal to a mux select line # - a multiplexer, which handles multiplexing e.g. payload signals # - a set of OR'ing logic, which joints together our simple or'd signals # Create our encoder... m.submodules.encoder = encoder = Encoder(len(self._inputs)) for index, interface in enumerate(self._inputs): # ... and tie its inputs to each of our 'valid' signals. valid_signal = getattr(interface, self._valid_field) m.d.comb += encoder.i[index].eq(valid_signal) # Create our multiplexer, and drive each of our output signals from it. with m.Switch(encoder.o): for index, interface in enumerate(self._inputs): # If an interface is selected... with m.Case(index): for identifier in self._mux_signals: # ... connect all of its muxed signals through to the output. output_signal = self._get_signal(self.output, identifier) input_signal = self._get_signal(interface, identifier) m.d.comb += output_signal.eq(input_signal) # Create the OR'ing logic for each of or or_signals. for identifier in self._or_signals: # Figure out the signals we want to work with... output_signal = self._get_signal(self.output, identifier) input_signals = (self._get_signal(i, identifier) for i in self._inputs) # ... and OR them together. or_reduced = functools.reduce(operator.__or__, input_signals, 0) m.d.comb += output_signal.eq(or_reduced) # Finally, pass each of our pass-back signals from the output interface # back to each of our input interfaces. for identifier in self._pass_signals: output_signal = self._get_signal(self.output, identifier) for interface in self._inputs: input_signal = self._get_signal(interface, identifier) m.d.comb += input_signal.eq(output_signal) return m
def elaborate(self, platform): assert Funct3.SLLI == Funct3.SLL assert Funct3.SRL == Funct3.SRLI assert Funct3.SRA == Funct3.SRAI m = Module() with m.Switch(self.funct3): with m.Case(Funct3.SLL): m.d.comb += self.res.eq(self.src1 << self.shift) with m.Case(Funct3.SRL): assert Funct3.SRL == Funct3.SRA assert Funct7.SRL != Funct7.SRA with m.If(self.funct7 == Funct7.SRL): m.d.comb += self.res.eq(self.src1 >> self.shift) with m.Elif(self.funct7 == Funct7.SRA): m.d.comb += [ self.src1signed.eq(self.src1), self.res.eq(self.src1signed >> self.shift), ] return m
def elaborate(self, platform): m = Module() with m.Switch(self.funct3): with m.Case(Funct3.SLT): m.d.comb += self.condition_met.eq(self.negative | self.overflow) with m.Case(Funct3.SLTU): m.d.comb += self.condition_met.eq(self.carry) with m.Case(Funct3.BEQ): m.d.comb += self.condition_met.eq(self.zero) with m.Case(Funct3.BNE): m.d.comb += self.condition_met.eq(~self.zero) with m.Case(Funct3.BLT): m.d.comb += self.condition_met.eq(self.negative ^ self.overflow) with m.Case(Funct3.BGE): m.d.comb += self.condition_met.eq(~(self.negative ^ self.overflow)) with m.Case(Funct3.BLTU): m.d.comb += self.condition_met.eq(self.carry) with m.Case(Funct3.BGEU): m.d.comb += self.condition_met.eq(~self.carry) return m
def elaborate(self, platform): m = Module() # Synchronize the USB signals at our I/O boundary. # Despite the assumptions made in ValentyUSB, this line rate recovery FSM # isn't enough to properly synchronize these inputs. We'll explicitly synchronize. sync_dp = synchronize(m, self._usbp, o_domain="usb_io") sync_dn = synchronize(m, self._usbn, o_domain="usb_io") ####################################################################### # 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. # dpair = Cat(sync_dp, sync_dn) # output signals for use by the clock recovery stage line_state_in_transition = Signal() with m.FSM(domain="usb_io") as fsm: m.d.usb_io += [ self.line_state_se0.eq(fsm.ongoing("SE0")), self.line_state_se1.eq(fsm.ongoing("SE1")), self.line_state_dj.eq(fsm.ongoing("DJ")), self.line_state_dk.eq(fsm.ongoing("DK")), ] # If we are in a transition state, then we can sample the pair and # move to the next corresponding line state. with m.State("DT"): m.d.comb += line_state_in_transition.eq(1) with m.Switch(dpair): with m.Case(0b10): m.next = "DJ" with m.Case(0b01): m.next = "DK" with m.Case(0b00): m.next = "SE0" with m.Case(0b11): m.next = "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. with m.State("DJ"): with m.If(dpair != 0b10): m.next = "DT" with m.State("DK"): with m.If(dpair != 0b01): m.next = "DT" with m.State("SE0"): with m.If(dpair != 0b00): m.next = "DT" with m.State("SE1"): with m.If(dpair != 0b11): m.next = "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) m.d.usb_io += self.line_state_valid.eq(line_state_phase == 1) with m.If(line_state_in_transition): m.d.usb_io += [ # 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), ] with m.Else(): # keep tracking the clock by incrementing the phase m.d.usb_io += line_state_phase.eq(line_state_phase + 1) return m
def elaborate(self, platform): m = Module() comb = m.d.comb sync = m.d.sync loadstore = self.loadstore store = self.store addr = Signal(32) comb += [ addr.eq(self.offset + self.src1), ] sel = m.submodules.sel = Selector() # sel.mask will be calculated. comb += [ sel.funct3.eq(self.funct3), sel.store.eq(store), ] word = Signal(signed(32)) half_word = Signal(signed(16)) byte = Signal(8) write_data = Signal(32) signed_write_data = Signal(signed(32)) load_res = Signal(signed(32)) addr_lsb = Signal(2) m.d.comb += addr_lsb.eq(addr[:2]) # XXX # allow naturally aligned addresses # TODO trap on wrong address with m.If(store): data = self.src2 comb += [ word.eq(data), half_word.eq(data.word_select(addr_lsb[1], 16)), byte.eq(data.word_select(addr_lsb, 8)), ] with m.Else(): data = loadstore.read_data comb += [ word.eq(data), half_word.eq(data.word_select(addr_lsb[1], 16)), byte.eq(data.word_select(addr_lsb, 8)) ] with m.If(~store): with m.Switch(self.funct3): with m.Case(Funct3.W): comb += load_res.eq(word) with m.Case(Funct3.H): comb += load_res.eq(half_word) with m.Case(Funct3.B): comb += load_res.eq(byte) with m.Case(Funct3.HU): comb += load_res.eq(Cat(half_word, 0)) with m.Case(Funct3.BU): comb += load_res.eq(Cat(byte, 0)) with m.If(store): with m.Switch(self.funct3): with m.Case(Funct3.W): comb += (write_data.eq(word), ) with m.Case(Funct3.H): comb += [ signed_write_data.eq(half_word), write_data.eq(signed_write_data), ] with m.Case(Funct3.B): comb += [ signed_write_data.eq(byte), write_data.eq(signed_write_data), ] with m.Case(Funct3.HU): comb += (write_data.eq(half_word), ) with m.Case(Funct3.BU): comb += (write_data.eq(byte), ) with m.If(self.en): comb += [ loadstore.en.eq(1), loadstore.store.eq(store), loadstore.addr.eq(addr), loadstore.mask.eq(sel.mask), loadstore.write_data.eq(write_data), ] with m.If(loadstore.ack): comb += [ self.ack.eq(1), self.res.eq(load_res), ] return m