def elaborate(self, platform): m = Module() # Generate our domain clocks/resets. m.submodules.car = platform.clock_domain_generator() # Create our USB device interface... ulpi = platform.request(platform.default_usb_connection) m.submodules.usb = usb = USBDevice(bus=ulpi) # Add our standard control endpoint to the device. descriptors = self.create_descriptors() usb.add_standard_control_endpoint(descriptors) # Add a stream endpoint to our device. stream_ep = USBStreamOutEndpoint( endpoint_number=self.BULK_ENDPOINT_NUMBER, max_packet_size=self.MAX_BULK_PACKET_SIZE) usb.add_endpoint(stream_ep) leds = Cat( platform.request_optional("led", i, default=NullPin()) for i in range(6)) user_io = Cat( platform.request_optional("user_io", i, default=NullPin()) for i in range(4)) # Always stream our USB data directly onto our User I/O and LEDS. with m.If(stream_ep.stream.valid): m.d.usb += [ leds.eq(stream_ep.stream.payload), user_io.eq(stream_ep.stream.payload), ] # Always accept data as it comes in. m.d.comb += stream_ep.stream.ready.eq(1) # Connect our device as a high speed device by default. m.d.comb += [ usb.connect.eq(1), usb.full_speed_only.eq(1 if os.getenv('LUNA_FULL_ONLY') else 0), ] return m
def elaborate(self, platform): m = Module() m.submodules.bridge = self._bridge # Grab our LEDS... leds = Cat(platform.request("led", i) for i in range(6)) # ... and update them on each register write. with m.If(self._output.w_stb): m.d.sync += leds.eq(self._output.w_data) 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() uart = platform.request("uart") clock_freq = int(60e6) char_freq = int(6e6) # Create our UART transmitter. transmitter = UARTTransmitter(divisor=int(clock_freq // 115200)) m.submodules.transmitter = transmitter stream = transmitter.stream # Create a counter that will let us transmit ten times per second. counter = Signal(range(0, char_freq)) with m.If(counter == (char_freq - 1)): m.d.sync += counter.eq(0) with m.Else(): m.d.sync += counter.eq(counter + 1) # Create a simple ROM with a message for ourselves... letters = Array(ord(i) for i in "Hello, world! \r\n") # ... and count through it whenever we send a letter. current_letter = Signal(range(0, len(letters))) with m.If(stream.ready): m.d.sync += current_letter.eq(current_letter + 1) # Hook everything up. m.d.comb += [ stream.payload.eq(letters[current_letter]), stream.valid.eq(counter == 0), uart.tx.o.eq(transmitter.tx), ] # If this platform has an output-enable control on its UART, drive it iff # we're actively driving a transmission. if hasattr(uart.tx, 'oe'): m.d.comb += uart.tx.oe.eq(transmitter.driving), # Turn on a single LED, just to show something's running. led = Cat(platform.request('led', i) for i in range(6)) m.d.comb += led.eq(~transmitter.tx) return m
def elaborate(self, platform): m = Module() # neat way of setting carry flag res_and_carry = Cat(self.res, self.carry) m.d.comb += res_and_carry.eq( Mux(self.sub, self.src1 - self.src2, self.src1 + self.src2)) with m.If(self.sub): with m.If((self.src1[-1] != self.src2[-1]) & (self.src1[-1] != self.res[-1])): m.d.comb += self.overflow.eq(1) with m.Else(): # add with m.If((self.src1[-1] == self.src2[-1]) & (self.src1[-1] != self.res[-1])): m.d.comb += self.overflow.eq(1) return m
def elaborate(self, platform): m = Module() board_spi = platform.request("debug_spi") # Create a set of registers, and expose them over SPI. spi_registers = SPIRegisterInterface(default_read_value=0x4C554E41) #default read = u'LUNA' m.submodules.spi_registers = spi_registers # Fill in some example registers. # (Register 0 is reserved for size autonegotiation). spi_registers.add_read_only_register(1, read=0xc001cafe) led_reg = spi_registers.add_register(2, size=6, name="leds") spi_registers.add_read_only_register(3, read=0xdeadbeef) # ... and tie our LED register to our LEDs. led_out = Cat([platform.request_optional("led", i, default=NullPin()).o for i in range(0, 8)]) m.d.comb += led_out.eq(led_reg) # Connect up our synchronized copies of the SPI registers. spi = synchronize(m, board_spi) m.d.comb += spi_registers.spi.connect(spi) return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES) m.submodules.clocking = clocking registers = JTAGRegisterInterface(default_read_value=0xDEADBEEF) m.submodules.registers = registers # Simple applet ID register. registers.add_read_only_register(REGISTER_ID, read=0x54455354) # LED test register. led_reg = registers.add_register(REGISTER_LEDS, size=6, name="leds", reset=0b111111) led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # # Target power test register. # Note: these values assume you've populated the correct AP22814 for # your revision (AP22814As for rev0.2+, and AP22814Bs for rev0.1). # bits [1:0]: 0 = power off # 1 = provide A-port VBUS # 2 = pass through target VBUS # power_test_reg = Signal(3) power_test_write_strobe = Signal() power_test_write_value = Signal(2) registers.add_sfr(REGISTER_TARGET_POWER, read=power_test_reg, write_strobe=power_test_write_strobe, write_signal=power_test_write_value) # Store the values for our enable bits. with m.If(power_test_write_strobe): m.d.sync += power_test_reg[0:2].eq(power_test_write_value) # Decode the enable bits and control the two power supplies. power_a_port = platform.request("power_a_port") power_passthrough = platform.request("pass_through_vbus") with m.If(power_test_reg[0:2] == 1): m.d.comb += [power_a_port.eq(1), power_passthrough.eq(0)] with m.Elif(power_test_reg[0:2] == 2): m.d.comb += [power_a_port.eq(0), power_passthrough.eq(1)] with m.Else(): m.d.comb += [power_a_port.eq(0), power_passthrough.eq(0)] # # User IO GPIO registers. # # Data direction register. user_io_dir = registers.add_register(REGISTER_USER_IO_DIR, size=2) # Pin (input) state register. user_io_in = Signal(2) registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in) # Output value register. user_io_out = registers.add_register(REGISTER_USER_IO_OUT, size=2) # Grab and connect each of our user-I/O ports our GPIO registers. for i in range(2): pin = platform.request("user_io", i) m.d.comb += [ pin.oe.eq(user_io_dir[i]), user_io_in[i].eq(pin.i), pin.o.eq(user_io_out[i]) ] # # ULPI PHY windows # self.add_ulpi_registers(m, platform, ulpi_bus="target_phy", register_base=REGISTER_TARGET_ADDR) self.add_ulpi_registers(m, platform, ulpi_bus="host_phy", register_base=REGISTER_HOST_ADDR) self.add_ulpi_registers(m, platform, ulpi_bus="sideband_phy", register_base=REGISTER_SIDEBAND_ADDR) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus, **platform.ram_timings) m.submodules += psram psram_address_changed = Signal() psram_address = registers.add_register( REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset.eq(0), psram.single_page.eq(0), psram.perform_write.eq(0), psram.register_space.eq(1), psram.final_word.eq(1), psram.start_transfer.eq(psram_address_changed), psram.address.eq(psram_address), ] 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() # Parser parser = SPIParser(self.platform) m.submodules.parser = parser # Busy used to detect move or scanline in action # disabled "dispatching" busy = Signal() # Polynomal Move polynomal = Polynomal(self.platform) m.submodules.polynomal = polynomal if platform: board_spi = platform.request("debug_spi") spi = synchronize(m, board_spi) laserheadpins = platform.request("laserscanner") steppers = [res for res in get_all_resources(platform, "stepper")] bldc = platform.request("bldc") leds = [res.o for res in get_all_resources(platform, "led")] assert len(steppers) != 0 else: platform = self.platform self.spi = SPIBus() self.parser = parser self.pol = polynomal spi = synchronize(m, self.spi) self.laserheadpins = platform.laserhead self.steppers = steppers = platform.steppers self.busy = busy laserheadpins = platform.laserhead bldc = platform.bldc leds = platform.leds # Local laser signal clones enable_prism = Signal() lasers = Signal(2) # Laserscan Head if self.simdiode: laserhead = DiodeSimulator(platform=platform, addfifo=False) lh = laserhead m.d.comb += [ lh.enable_prism_in.eq(enable_prism | lh.enable_prism), lh.laser0in.eq(lasers[0] | lh.lasers[0]), laserhead.laser1in.eq(lasers[1] | lh.lasers[1]) ] else: laserhead = Laserhead(platform=platform) m.d.comb += laserhead.photodiode.eq(laserheadpins.photodiode) m.submodules.laserhead = laserhead if platform.name == 'Test': self.laserhead = laserhead # polynomal iterates over count coeffcnt = Signal(range(len(polynomal.coeff) + 1)) # Prism motor prism_driver = Driver(platform) m.submodules.prism_driver = prism_driver # connect prism motor for idx in range(len(leds)): m.d.comb += leds[idx].eq(prism_driver.leds[idx]) m.d.comb += prism_driver.enable_prism.eq(enable_prism) m.d.comb += [ bldc.uL.eq(prism_driver.uL), bldc.uH.eq(prism_driver.uH), bldc.vL.eq(prism_driver.vL), bldc.vH.eq(prism_driver.vH), bldc.wL.eq(prism_driver.wL), bldc.wH.eq(prism_driver.wH) ] m.d.comb += [ prism_driver.hall[0].eq(bldc.sensor0), prism_driver.hall[1].eq(bldc.sensor1), prism_driver.hall[2].eq(bldc.sensor2) ] # connect laserhead m.d.comb += [ # TODO: fix removal # laserheadpins.pwm.eq(laserhead.pwm), # laserheadpins.en.eq(laserhead.enable_prism | enable_prism), laserheadpins.laser0.eq(laserhead.lasers[0] | lasers[0]), laserheadpins.laser1.eq(laserhead.lasers[1] | lasers[1]), ] # connect Parser m.d.comb += [ self.read_data.eq(parser.read_data), laserhead.read_data.eq(parser.read_data), laserhead.empty.eq(parser.empty), self.empty.eq(parser.empty), parser.read_commit.eq(self.read_commit | laserhead.read_commit), parser.read_en.eq(self.read_en | laserhead.read_en), parser.read_discard.eq(self.read_discard | laserhead.read_discard) ] # connect motors for idx, stepper in enumerate(steppers): step = (polynomal.step[idx] & ((stepper.limit == 0) | stepper.dir)) if idx != (list(platform.stepspermm.keys()).index( platform.laser_axis)): direction = polynomal.dir[idx] m.d.comb += [ stepper.step.eq(step), stepper.dir.eq(direction), parser.pinstate[idx].eq(stepper.limit) ] # connect the motor in which the laserhead moves to laser core else: m.d.comb += [ parser.pinstate[idx].eq(stepper.limit), stepper.step.eq((step & (~laserhead.process_lines)) | (laserhead.step & (laserhead.process_lines))), stepper.dir.eq( (polynomal.dir[idx] & (~laserhead.process_lines)) | (laserhead.dir & (laserhead.process_lines))) ] m.d.comb += (parser.pinstate[len(steppers):].eq( Cat(laserhead.photodiode_t, laserhead.synchronized))) # update position stepper_d = Array(Signal() for _ in range(len(steppers))) for idx, stepper in enumerate(steppers): pos = parser.position[idx] m.d.sync += stepper_d[idx].eq(stepper.step) with m.If(stepper.limit == 1): m.d.sync += parser.position[idx].eq(0) # assuming position is signed # TODO: this might eat LUT, optimize pos_max = pow(2, pos.width - 1) - 2 with m.Elif((pos > pos_max) | (pos < -pos_max)): m.d.sync += parser.position[idx].eq(0) with m.Elif((stepper.step == 1) & (stepper_d[idx] == 0)): with m.If(stepper.dir): m.d.sync += pos.eq(pos + 1) with m.Else(): m.d.sync += pos.eq(pos - 1) # Busy signal m.d.comb += busy.eq(polynomal.busy | laserhead.process_lines) # connect spi m.d.comb += parser.spi.connect(spi) # pins you can write to pins = Cat(lasers, enable_prism, laserhead.synchronize) with m.FSM(reset='RESET', name='dispatcher'): with m.State('RESET'): m.next = 'WAIT_INSTRUCTION' m.d.sync += pins.eq(0) with m.State('WAIT_INSTRUCTION'): m.d.sync += [self.read_commit.eq(0), polynomal.start.eq(0)] with m.If((self.empty == 0) & parser.parse & (busy == 0)): m.d.sync += self.read_en.eq(1) m.next = 'PARSEHEAD' # check which instruction we r handling with m.State('PARSEHEAD'): byte0 = self.read_data[:8] m.d.sync += self.read_en.eq(0) with m.If(byte0 == INSTRUCTIONS.MOVE): m.d.sync += [ polynomal.ticklimit.eq(self.read_data[8:]), coeffcnt.eq(0) ] m.next = 'MOVE_POLYNOMAL' with m.Elif(byte0 == INSTRUCTIONS.WRITEPIN): m.d.sync += [ pins.eq(self.read_data[8:]), self.read_commit.eq(1) ] m.next = 'WAIT' with m.Elif((byte0 == INSTRUCTIONS.SCANLINE) | (byte0 == INSTRUCTIONS.LASTSCANLINE)): m.d.sync += [ self.read_discard.eq(1), laserhead.synchronize.eq(1), laserhead.expose_start.eq(1) ] m.next = 'SCANLINE' with m.Else(): m.next = 'ERROR' m.d.sync += parser.dispatcherror.eq(1) with m.State('MOVE_POLYNOMAL'): with m.If(coeffcnt < len(polynomal.coeff)): with m.If(self.read_en == 0): m.d.sync += self.read_en.eq(1) with m.Else(): m.d.sync += [ polynomal.coeff[coeffcnt].eq(self.read_data), coeffcnt.eq(coeffcnt + 1), self.read_en.eq(0) ] with m.Else(): m.next = 'WAIT' m.d.sync += [polynomal.start.eq(1), self.read_commit.eq(1)] with m.State('SCANLINE'): m.d.sync += [ self.read_discard.eq(0), laserhead.expose_start.eq(0) ] m.next = 'WAIT' # NOTE: you need to wait for busy to be raised # in time with m.State('WAIT'): m.d.sync += polynomal.start.eq(0) m.next = 'WAIT_INSTRUCTION' # NOTE: system never recovers user must reset with m.State('ERROR'): m.next = 'ERROR' return m
def elaborate(self, platform): m = Module() m.submodules.ila = ila = self.ila if self._o_domain == self.domain: in_domain_stream = self.stream else: in_domain_stream = StreamInterface( payload_width=self.bits_per_sample) # Count where we are in the current transmission. current_sample_number = Signal(range(0, ila.sample_depth)) # Always present the current sample number to our ILA, and the current # sample value to the UART. m.d.comb += [ ila.captured_sample_number.eq(current_sample_number), in_domain_stream.payload.eq(ila.captured_sample) ] with m.FSM(): # IDLE -- we're currently waiting for a trigger before capturing samples. with m.State("IDLE"): # Always allow triggering, as we're ready for the data. m.d.comb += self.ila.trigger.eq(self.trigger) # Once we're triggered, move onto the SAMPLING state. with m.If(self.trigger): m.next = "SAMPLING" # SAMPLING -- the internal ILA is sampling; we're now waiting for it to # complete. This state is similar to IDLE; except we block triggers in order # to cleanly avoid a race condition. with m.State("SAMPLING"): # Once our ILA has finished sampling, prepare to read out our samples. with m.If(self.ila.complete): m.d.sync += [ current_sample_number.eq(0), in_domain_stream.first.eq(1) ] m.next = "SENDING" # SENDING -- we now have a valid buffer of samples to send up to the host; # we'll transmit them over our stream interface. with m.State("SENDING"): data_valid = Signal(reset=1) m.d.comb += [ # While we're sending, we're always providing valid data to the UART. in_domain_stream.valid.eq(data_valid), # Indicate when we're on the last sample. in_domain_stream.last.eq( current_sample_number == (self.sample_depth - 1)) ] # Each time the UART accepts a valid word, move on to the next one. with m.If(in_domain_stream.ready): with m.If(data_valid): m.d.sync += [ current_sample_number.eq(current_sample_number + 1), data_valid.eq(0), in_domain_stream.first.eq(0) ] # If this was the last sample, we're done! Move back to idle. with m.If(self.stream.last): m.next = "IDLE" with m.Else(): m.d.sync += data_valid.eq(1) # If we're not streaming out of the same domain we're capturing from, # we'll add some clock-domain crossing hardware. if self._o_domain != self.domain: in_domain_signals = Cat(in_domain_stream.first, in_domain_stream.payload, in_domain_stream.last) out_domain_signals = Cat(self.stream.first, self.stream.payload, self.stream.last) # Create our async FIFO... m.submodules.cdc = fifo = AsyncFIFOBuffered( width=len(in_domain_signals), depth=16, w_domain="sync", r_domain=self._o_domain) m.d.comb += [ # ... fill it from our in-domain stream... fifo.w_data.eq(in_domain_signals), fifo.w_en.eq(in_domain_stream.valid), in_domain_stream.ready.eq(fifo.w_rdy), # ... and output it into our outupt stream. out_domain_signals.eq(fifo.r_data), self.stream.valid.eq(fifo.r_rdy), fifo.r_en.eq(self.stream.ready) ] # Convert our sync domain to the domain requested by the user, if necessary. if self.domain != "sync": m = DomainRenamer(self.domain)(m) return m
def provide_all_signals(self, value): all_signals = Cat(self.input_a, self.input_b, self.input_c) yield all_signals.eq(value)