Example #1
0
    def elaborate(self, platform):
        """ Generate the Blinky tester. """

        m = Module()

        # Grab our I/O connectors.
        leds = [
            platform.request_optional("led", i, default=NullPin()).o
            for i in range(0, 8)
        ]
        user_io = [
            platform.request_optional("user_io", i, default=NullPin()).o
            for i in range(0, 8)
        ]

        # Clock divider / counter.
        counter = Signal(28)
        m.d.sync += counter.eq(counter + 1)

        # Attach the LEDs and User I/O to the MSBs of our counter.
        m.d.comb += Cat(leds).eq(counter[-7:-1])
        m.d.comb += Cat(user_io).eq(counter[7:21])

        # Return our elaborated module.
        return m
Example #2
0
    def elab(self, m):
        # Unset valid on transfer (may be overrridden below)
        with m.If(self.output.ready):
            m.d.sync += self.output.valid.eq(0)

        # Set flag to remember that value is available
        flags = Array(Signal(name=f"flag_{i}") for i in range(8))
        for i in range(8):
            with m.If(self.accumulator_new[i]):
                m.d.sync += flags[i].eq(1)

        # Calculate index of value to output
        index = Signal(range(8))
        next_index = Signal(range(8))
        with m.If(self.half_mode):
            # counts: 0, 1, 4, 5, 0 ...
            m.d.comb += next_index[1].eq(0)
            m.d.comb += Cat(next_index[0], next_index[2]
                            ).eq(Cat(index[0], index[2]) + 1)
        with m.Else():
            m.d.comb += next_index.eq(index + 1)

        # If value available this cycle, or previously
        # - output new value
        # - unset flag
        # - increment index
        with m.If(Array(self.accumulator_new)[index] | flags[index]):
            m.d.sync += [
                self.output.payload.eq(Array(self.accumulator)[index]),
                self.output.valid.eq(1),
                flags[index].eq(0),
                index.eq(next_index),
            ]
Example #3
0
    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
Example #4
0
    def populate_ulpi_registers(self, m):
        """ Creates translator objects that map our control signals to ULPI registers. """

        # Function control.
        function_control = Cat(self.xcvr_select, self.term_select, self.op_mode, Const(0), ~self.suspend, Const(0))
        self.add_composite_register(m, 0x04, function_control, reset_value=0b01000001)

        # OTG control.
        otg_control = Cat(
            self.id_pullup, self.dp_pulldown, self.dm_pulldown, self.dischrg_vbus,
            self.chrg_vbus, Const(0), Const(0), self.use_external_vbus_indicator
        )
        self.add_composite_register(m, 0x0A, otg_control, reset_value=0b00000110)
Example #5
0
    def _elab_write(self, m, dps, r_full):
        w_curr_buf = Signal()
        # Address within current buffer
        w_addr = Signal.like(self.input_depth)

        # Connect to memory write port
        for n, dp in enumerate(dps):
            m.d.comb += [
                dp.w_addr.eq(Cat(w_addr[2:], w_curr_buf)),
                dp.w_data.eq(self.w_data),
                dp.w_en.eq(self.w_en & self.w_ready & (n == w_addr[:2])),
            ]
        # Ready to write current buffer if reading is not allowed
        m.d.comb += self.w_ready.eq(~r_full[w_curr_buf])

        # Write address increment
        with m.If(self.w_en & self.w_ready):
            with m.If(w_addr == self.input_depth - 1):
                # at end of buffer - mark buffer ready for reading and go to
                # next
                m.d.sync += [
                    w_addr.eq(0),
                    r_full[w_curr_buf].eq(1),
                    w_curr_buf.eq(~w_curr_buf),
                ]
            with m.Else():
                m.d.sync += w_addr.eq(w_addr + 1)

        with m.If(self.restart):
            m.d.sync += [
                w_addr.eq(0),
                w_curr_buf.eq(0),
            ]
Example #6
0
    def _elab_read(self, m, dps, r_full):
        r_curr_buf = Signal()
        # Address within current buffer
        r_addr = Signal.like(self.input_depth)

        # Create and connect sequential memory readers
        smrs = [
            SequentialMemoryReader(max_depth=self.max_depth // 2, width=32)
            for _ in range(4)
        ]
        for (n, dp, smr) in zip(range(4), dps, smrs):
            m.submodules[f"smr_{n}"] = smr
            m.d.comb += [
                dp.r_addr.eq(Cat(smr.mem_addr, r_curr_buf)),
                smr.mem_data.eq(dp.r_data),
                smr.limit.eq((self.input_depth + 3 - n) >> 2),
            ]

        smr_nexts = Array(smr.next for smr in smrs)

        # Ready if current buffer is full
        full = Signal()
        m.d.comb += full.eq(r_full[r_curr_buf])
        last_full = Signal()
        m.d.sync += last_full.eq(full)
        with m.If(full & ~last_full):
            m.d.sync += self.r_ready.eq(1)
            m.d.comb += [smr.restart.eq(1) for smr in smrs]

        # Increment address
        with m.If(self.r_next & self.r_ready):
            with m.If(r_addr == self.input_depth - 1):
                m.d.sync += r_addr.eq(0)
            with m.Else():
                m.d.sync += r_addr.eq(r_addr + 1)
            m.d.comb += smr_nexts[r_addr[:2]].eq(1)

        # Get data
        smr_datas = Array(smr.data for smr in smrs)
        m.d.comb += self.r_data.eq(smr_datas[r_addr[:2]])

        # On finished (overrides r_next)
        with m.If(self.r_finished):
            m.d.sync += [
                r_addr.eq(0),
                r_full[r_curr_buf].eq(0),
                last_full.eq(0),
                self.r_ready.eq(0),
                r_curr_buf.eq(~r_curr_buf),
            ]

        # On restart, reset addresses and Sequential Memory readers, go to not
        # ready
        with m.If(self.restart):
            m.d.sync += [
                r_addr.eq(0),
                last_full.eq(0),
                self.r_ready.eq(0),
                r_curr_buf.eq(0),
            ]
Example #7
0
    def elaborate(self, platform):
        m = Module()
        m.submodules += self.ila

        # Generate our clock domains.
        clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES)
        m.submodules.clocking = clocking

        # Clock divider / counter.
        m.d.fast += self.counter.eq(self.counter + 1)

        # Set our ILA to trigger each time the counter is at a random value.
        # This shows off our example a bit better than counting at zero.
        m.d.comb += self.ila.trigger.eq(self.counter == 7)

        # Grab our I/O connectors.
        leds = [platform.request("led", i, dir="o") for i in range(0, 6)]
        spi_bus = synchronize(m,
                              platform.request('debug_spi'),
                              o_domain='fast')

        # Attach the LEDs and User I/O to the MSBs of our counter.
        m.d.comb += Cat(leds).eq(self.counter[-7:-1])

        # Connect our ILA up to our board's aux SPI.
        m.d.comb += self.ila.spi.connect(spi_bus)

        # Return our elaborated module.
        return m
Example #8
0
    def __init__(self,
                 *,
                 signals,
                 sample_depth,
                 domain="sync",
                 sample_rate=60e6,
                 samples_pretrigger=1):
        self.domain = domain
        self.signals = signals
        self.inputs = Cat(*signals)
        self.sample_width = len(self.inputs)
        self.sample_depth = sample_depth
        self.samples_pretrigger = samples_pretrigger
        self.sample_rate = sample_rate
        self.sample_period = 1 / sample_rate

        #
        # Create a backing store for our samples.
        #
        self.mem = Memory(width=self.sample_width,
                          depth=sample_depth,
                          name="ila_buffer")

        #
        # I/O port
        #
        self.trigger = Signal()
        self.sampling = Signal()
        self.complete = Signal()

        self.captured_sample_number = Signal(range(0, self.sample_depth))
        self.captured_sample = Signal(self.sample_width)
Example #9
0
    def elab(self, m):
        # number of bytes received already
        byte_count = Signal(range(4))
        # output channel for next byte received
        pixel_index = Signal(range(self._num_pixels))
        # shift registers to buffer 3 incoming values
        shift_registers = Array(
            [Signal(24, name=f"sr_{i}") for i in range(self._num_pixels)])

        last_pixel_index = Signal.like(pixel_index)
        m.d.sync += last_pixel_index.eq(Mux(self.half_mode,
                                            self._num_pixels // 2 - 1,
                                            self._num_pixels - 1))
        next_pixel_index = Signal.like(pixel_index)
        m.d.comb += next_pixel_index.eq(Mux(pixel_index == last_pixel_index,
                                            0, pixel_index + 1))

        m.d.comb += self.input.ready.eq(1)
        with m.If(self.input.is_transferring()):
            sr = shift_registers[pixel_index]
            with m.If(byte_count == 3):
                # Output current value and shift register
                m.d.comb += self.output.valid.eq(1)
                payload = Cat(sr, self.input.payload)
                m.d.comb += self.output.payload.eq(payload)
            with m.Else():
                # Save input to shift register
                m.d.sync += sr[-8:].eq(self.input.payload)
                m.d.sync += sr[:-8].eq(sr[8:])

            # Increment pixel index
            m.d.sync += pixel_index.eq(next_pixel_index)
            with m.If(pixel_index == last_pixel_index):
                m.d.sync += pixel_index.eq(0)
                m.d.sync += byte_count.eq(byte_count + 1)  # allow rollover
Example #10
0
 def trap(cause: Optional[Union[TrapCause, IrqCause]], interrupt=False):
     fetch_with_new_pc(Cat(Const(0, 2), self.csr_unit.mtvec.base))
     if cause is None:
         return
     assert isinstance(cause, TrapCause) or isinstance(cause, IrqCause)
     e = exception_unit
     notifiers = e.irq_cause_map if interrupt else e.trap_cause_map
     m.d.comb += notifiers[cause].eq(1)
Example #11
0
    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
Example #12
0
    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
Example #13
0
    def elaborate(self, platform):
        m = Module()
        m.submodules += self.ila

        # Grab a reference to our debug-SPI bus.
        board_spi = synchronize(m, platform.request("debug_spi"))

        # Clock divider / counter.
        m.d.sync += self.counter.eq(self.counter + 1)

        # Another example signal, for variety.
        m.d.sync += self.toggle.eq(~self.toggle)

        # Create an SPI bus for our ILA.
        ila_spi = SPIBus()
        m.d.comb += [
            self.ila.spi .connect(ila_spi),

            # For sharing, we'll connect the _inverse_ of the primary
            # chip select to our ILA bus. This will allow us to send
            # ILA data when CS is un-asserted, and register data when
            # CS is asserted.
            ila_spi.cs  .eq(~board_spi.cs)
        ]

        # Create a set of registers...
        spi_registers = SPIRegisterInterface()
        m.submodules.spi_registers = spi_registers

        # ... and an SPI bus for them.
        reg_spi = SPIBus()
        m.d.comb += [
            spi_registers.spi .connect(reg_spi),
            reg_spi.cs        .eq(board_spi.cs)
        ]

        # Multiplex our ILA and register SPI busses.
        m.submodules.mux = SPIMultiplexer([ila_spi, reg_spi])
        m.d.comb += m.submodules.mux.shared_lines.connect(board_spi)

        # Add a simple ID register to demonstrate our registers.
        spi_registers.add_read_only_register(REGISTER_ID, read=0xDEADBEEF)

        # Create a simple SFR that will trigger an ILA capture when written,
        # and which will display our sample status read.
        spi_registers.add_sfr(REGISTER_ILA,
            read=self.ila.complete,
            write_strobe=self.ila.trigger
        )

        # Attach the LEDs and User I/O to the MSBs of our counter.
        leds    = [platform.request("led", i, dir="o") for i in range(0, 6)]
        m.d.comb += Cat(leds).eq(self.counter[-7:-1])

        # Return our elaborated module.
        return m
Example #14
0
    def elab(self, m):
        register = Signal(32)
        m.d.comb += self.result.eq(register)

        with m.If(self.shift_en):
            calc = Signal(32)
            m.d.comb += [
                calc.eq(Cat(register[8:], self.in_value)),
                self.result.eq(calc),
            ]
            m.d.sync += register.eq(calc)
Example #15
0
    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
Example #16
0
 def max_(word0, word1):
     result = [Signal(8, name=f"result{i}") for i in range(4)]
     bytes0 = [word0[i:i + 8] for i in range(0, 32, 8)]
     bytes1 = [word1[i:i + 8] for i in range(0, 32, 8)]
     for r, b0, b1 in zip(result, bytes0, bytes1):
         sb0 = Signal(signed(8))
         m.d.comb += sb0.eq(b0)
         sb1 = Signal(signed(8))
         m.d.comb += sb1.eq(b1)
         m.d.comb += r.eq(Mux(sb1 > sb0, b1, b0))
     return Cat(*result)
Example #17
0
    def _split_samples(self, all_samples):
        """ Returns an iterator that iterates over each sample in the raw binary of samples. """
        from apollo_fpga.support.bits import bits

        sample_width_bytes = self.ila.bytes_per_sample

        # Iterate over each sample, and yield its value as a bits object.
        for i in range(0, len(all_samples), sample_width_bytes):
            raw_sample    = all_samples[i:i + sample_width_bytes]
            sample_length = len(Cat(self.ila.signals))

            yield bits.from_bytes(raw_sample, length=sample_length, byteorder='little')
Example #18
0
    def elaborate(self, platform):
        m = Module()
        width = self._width

        # Instead of using a counter, we will use a sentinel bit in the shift
        # register to indicate when it is full.
        shift_reg = Signal(width + 1, reset=0b1)

        m.d.comb += self.o_data.eq(shift_reg[0:width])
        m.d.usb_io += self.o_put.eq(shift_reg[width - 1] & ~shift_reg[width]
                                    & self.i_valid),

        with m.If(self.reset):
            m.d.usb_io += shift_reg.eq(1)

        with m.If(self.i_valid):
            with m.If(shift_reg[width]):
                m.d.usb_io += shift_reg.eq(Cat(self.i_data, Const(1)))
            with m.Else():
                m.d.usb_io += shift_reg.eq(Cat(self.i_data,
                                               shift_reg[0:width])),

        return m
Example #19
0
 def elab(self, m):
     m.d.comb += [
         self.done.eq(True),
         self.w_addr.eq(self.count[self.num_memories_bits:]),
         self.updated.eq(Cat(self.w_en).any() | self.restart),
     ]
     with m.If(self.restart):
         m.d.sync += self.count.eq(0)
     with m.Elif(self.start):
         m.d.comb += [
             self.w_en[self.count[:self.num_memories_bits]].eq(1),
             self.w_data.eq(self.in0),
         ]
         m.d.sync += self.count.eq(self.count + 1)
Example #20
0
        def uart_gen_serial_record(platform: Platform, m: Module):
            if platform:
                serial = platform.request("uart")
                debug = platform.request("debug")
                m.d.comb += [
                    debug.eq(Cat(
                        serial.tx,
                        Const(0, 1),  # GND
                    ))
                ]
            else:
                serial = Record(Layout([("tx", 1)]), name="UART_SERIAL")
            self.serial = serial  # TODO this is obfuscated, but we need those signals for simulation testbench

            return serial
Example #21
0
    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
Example #22
0
def delay(m, signal, interval, *, out=None):
    """ Creates a delayed copy of a given I/O signal.

    Currently only works at the FPGA's I/O boundary, and only on ECP5s.

    Parameters:
        signal -- The signal to be delayed. Must be either an I/O
                  signal connected directly to a platform resource.
        delay  -- Delay, in arbitrary units. These units will vary
                  from unit to unit, but seem to be around 300ps on
                  most ECP5 FPGAs. On ECP5s, maxes out at 127.
        out    -- The signal to received the delayed signal; or
                  None ot have a signal created for you.

    Returns:
        delayed -- The delayed signal. Will be equivalent to 'out'
                   if provided; or a new signal otherwise.
    """

    # If we're not being passed our output signal, create one.
    if out is None:
        out = Signal.like(signal)

    # If we have more than one signal, call this function on each
    # of the subsignals.
    if len(signal) > 1:

        # If we have a vector of signals, but a integer delay,
        # convert that integer to a vector of same-valued delays.
        if isinstance(interval, int):
            interval = [interval] * len(signal)

        return Cat(
            delay(m, s, d, out=o) for s, d, o in zip(signal, interval, out))

    #
    # Base case: create a delayed version of the relevant signal.
    #
    m.submodules += Instance("DELAYG",
                             i_A=signal,
                             o_Z=out,
                             p_DEL_VALUE=interval)

    return out
Example #23
0
    def elab(self, m: Module):
        rp_data = []
        for i in range(4):
            mem = Memory(depth=self._depth // 4, width=32)
            # Set up read port
            m.submodules[f'rp_{i}'] = rp = mem.read_port(transparent=False)
            rp_data.append(rp.data)
            m.d.comb += rp.addr.eq(self.read_addr)
            m.d.comb += rp.en.eq(~self.write_enable)

            # Set up write port
            m.submodules[f'wp_{i}'] = wp = mem.write_port()
            m.d.comb += wp.addr.eq(self.write_addr[2:])
            m.d.comb += wp.data.eq(self.write_data)
            m.d.comb += wp.en.eq(self.write_enable
                                 & (i == self.write_addr[:2]))

        # Assemble all of the read port outputs into one, 128bit wide signal
        m.d.comb += self.read_data.eq(Cat(rp_data))
Example #24
0
    def elab(self, m):
        # This code covers 8 cases, determined by bits 1, 2 and 3 of self.addr.
        # First, bit 2 and 3 are used to select the appropriate ram_mux phase
        # and addresses in order to read the two words containing the required
        # data via channels 0 and 3 of the RAM Mux. Once the two words have been
        # retrieved, six bytes are selected from those two words based on the
        # value of bit 1 of self.addr.

        # Uses just two of the mux channels - 0 and 3
        # For convenience, tie the unused addresses to zero
        m.d.comb += self.ram_mux_addr[1].eq(0)
        m.d.comb += self.ram_mux_addr[2].eq(0)

        # Calculate block addresses of the two words - second word may cross 16
        # byte block boundary
        block = Signal(14)
        m.d.comb += block.eq(self.addr[4:])
        m.d.comb += self.ram_mux_addr[0].eq(block)
        m.d.comb += self.ram_mux_addr[3].eq(
            Mux(self.ram_mux_phase == 3, block + 1, block))

        # Use phase to select the two required words to channels 0 & 3
        m.d.comb += self.ram_mux_phase.eq(self.addr[2:4])

        # Select correct three half words when data is available, on cycle after
        # address received.
        byte_sel = Signal(1)
        m.d.sync += byte_sel.eq(self.addr[1])
        d0 = self.ram_mux_data[0]
        d3 = self.ram_mux_data[3]
        dmix = Signal(32)
        m.d.comb += dmix.eq(Cat(d0[16:], d3[:16]))
        with m.If(byte_sel == 0):
            m.d.comb += self.data_out[0].eq(d0)
            m.d.sync += self.data_out[1].eq(dmix)
        with m.Else():
            m.d.comb += self.data_out[0].eq(dmix)
            m.d.sync += self.data_out[1].eq(d3)
Example #25
0
    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
Example #26
0
    def elab(self, m: Module):

        # Registers accumulate incoming values
        registers = [Signal(8, name="register{i}") for i in range(3)]
        waiting_to_send = Signal()

        # Handle accumulating values
        with m.FSM(reset="BYTE_0"):
            with m.State("BYTE_0"):
                m.d.comb += self.input.ready.eq(1)
                m.d.sync += registers[0].eq(self.input.payload)
                with m.If(self.input.is_transferring()):
                    m.next = "BYTE_1"
            with m.State("BYTE_1"):
                m.d.comb += self.input.ready.eq(1)
                m.d.sync += registers[1].eq(self.input.payload)
                with m.If(self.input.is_transferring()):
                    m.next = "BYTE_2"
            with m.State("BYTE_2"):
                m.d.comb += self.input.ready.eq(1)
                m.d.sync += registers[2].eq(self.input.payload)
                with m.If(self.input.is_transferring()):
                    m.next = "BYTE_3"
            with m.State("BYTE_3"):
                m.d.comb += self.input.ready.eq(~waiting_to_send)
                with m.If(self.input.is_transferring()):
                    m.d.sync += waiting_to_send.eq(1)
                    m.d.sync += self.output.payload.eq(
                        Cat(registers[0], registers[1], registers[2],
                            self.input.payload))
                    m.next = "BYTE_0"

        # Handle output whenever ready
        m.d.comb += self.output.valid.eq(waiting_to_send)
        with m.If(self.output.is_transferring()):
            m.d.sync += waiting_to_send.eq(0)
Example #27
0
 def elaborate(self, platform):
     m = Module()
     ac = Signal(self.width+1)
     ac_next = Signal.like(ac)
     temp = Signal.like(ac)
     q1 = Signal(self.width)
     q1_next = Signal.like(q1)
     i = Signal(range(self.width))
     # combinatorial
     with m.If(ac >= self.y):
         m.d.comb += [temp.eq(ac-self.y),
                      Cat(q1_next, ac_next).eq(
                      Cat(1, q1, temp[0:self.width-1]))]
     with m.Else():
         m.d.comb += [Cat(q1_next, ac_next).eq(Cat(q1, ac) << 1)]
     # synchronized
     with m.If(self.start):
         m.d.sync += [self.valid.eq(0), i.eq(0)]
         with m.If(self.y == 0):
             m.d.sync += [self.busy.eq(0),
                          self.dbz.eq(1)]
         with m.Else():
             m.d.sync += [self.busy.eq(1),
                          self.dbz.eq(0),
                          Cat(q1, ac).eq(Cat(Const(0, 1),
                                         self.x, Const(0, self.width)))]
     with m.Elif(self.busy):
         with m.If(i == self.width-1):
             m.d.sync += [self.busy.eq(0),
                          self.valid.eq(1),
                          i.eq(0),
                          self.q.eq(q1_next),
                          self.r.eq(ac_next >> 1)]
         with m.Else():
             m.d.sync += [i.eq(i+1),
                          ac.eq(ac_next),
                          q1.eq(q1_next)]
     return m
Example #28
0
    def elaborate(self, platform):
        m = Module()

        # Grab signals that detect when we should shift in and out.
        sample_edge, output_edge = self.spi_edge_detectors(m)

        # We'll use separate buffers for transmit and receive,
        # as this makes the code a little more readable.
        bit_count = Signal(range(0, self.word_size), reset=0)
        current_tx = Signal.like(self.word_out)
        current_rx = Signal.like(self.word_in)

        # Signal that tracks if this is our first bit of the word.
        is_first_bit = Signal()

        # A word is ready one cycle after we complete a transaction
        # (and latch in the next word to be sent).
        with m.If(self.word_accepted):
            m.d.sync += [self.word_in.eq(current_rx), self.word_complete.eq(1)]
        with m.Else():
            m.d.sync += self.word_complete.eq(0)

        # De-assert our control signals unless explicitly asserted.
        m.d.sync += [
            self.word_accepted.eq(0),
        ]

        # If the chip is selected, process our I/O:
        chip_selected = self.spi.cs if not self.cs_idles_high else ~self.spi.cs

        with m.If(chip_selected):

            # Shift in data on each sample edge.
            with m.If(sample_edge):
                m.d.sync += [bit_count.eq(bit_count + 1), is_first_bit.eq(0)]

                if self.msb_first:
                    m.d.sync += current_rx.eq(
                        Cat(self.spi.sdi, current_rx[:-1]))
                else:
                    m.d.sync += current_rx.eq(Cat(current_rx[1:],
                                                  self.spi.sdi))

                # If we're just completing a word, handle I/O.
                with m.If(bit_count + 1 == self.word_size):
                    m.d.sync += [
                        self.word_accepted.eq(1),
                        current_tx.eq(self.word_out)
                    ]

            # Shift out data on each output edge.
            with m.If(output_edge):
                if self.msb_first:
                    m.d.sync += Cat(current_tx[1:],
                                    self.spi.sdo).eq(current_tx)
                else:
                    m.d.sync += Cat(self.spi.sdo,
                                    current_tx[:-1]).eq(current_tx)

        with m.Else():
            m.d.sync += [
                current_tx.eq(self.word_out),
                bit_count.eq(0),
                is_first_bit.eq(1)
            ]

        return m
Example #29
0
    def elaborate(self, platform):

        m = Module()
        spi = self.spi

        sample_edge = Fell(spi.sck, domain="sync")

        # 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() as fsm:
            m.d.comb += [
                self.idle.eq(fsm.ongoing('IDLE')),
                self.stalled.eq(fsm.ongoing('STALL')),
            ]

            # 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'):

                # If CS is de-asserted early; our transaction is being aborted.
                with m.If(~spi.cs):
                    m.next = 'IDLE'

                # 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'):

                # If CS is de-asserted early; our transaction is being aborted.
                with m.If(~spi.cs):
                    m.next = 'IDLE'

                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
Example #30
0
    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