예제 #1
0
 def __init__(self):
     super().__init__()
     self.reg_fifo_items_value = Signal(32)
     self.reg_verify_value = Signal(32)
     self.output_words = Endpoint(unsigned(32))
예제 #2
0
    def __init__(self, *, bus, handle_clocking=True):
        """
        Parameters:
        """

        # If this looks more like a ULPI bus than a UTMI bus, translate it.
        if hasattr(bus, 'dir'):
            self.utmi = UTMITranslator(ulpi=bus,
                                       handle_clocking=handle_clocking)
            self.bus_busy = self.utmi.busy
            self.translator = self.utmi
            self.always_fs = False
            self.data_clock = 60e6

        # If this looks more like raw I/O connections than a UTMI bus, create a pure-gatware
        # PHY to drive the raw I/O signals.
        elif hasattr(bus, 'd_n'):
            self.utmi = GatewarePHY(io=bus)
            self.bus_busy = Const(0)
            self.translator = self.utmi
            self.always_fs = True
            self.data_clock = 12e6

        # Otherwise, use it directly.
        # Note that since a true UTMI interface has separate Tx/Rx/control
        # interfaces, we don't need to care about bus 'busyness'; so we'll
        # set it to a const zero.
        else:
            self.utmi = bus
            self.bus_busy = Const(0)
            self.translator = None
            self.always_fs = True
            self.data_clock = 12e6

        #
        # I/O port
        #
        self.connect = Signal()
        self.low_speed_only = Signal()
        self.full_speed_only = Signal()

        self.frame_number = Signal(11)
        self.microframe_number = Signal(3)
        self.sof_detected = Signal()
        self.new_frame = Signal()
        self.reset_detected = Signal()

        self.speed = Signal(2)
        self.suspended = Signal()
        self.tx_activity_led = Signal()
        self.rx_activity_led = Signal()

        #
        # Internals.
        #
        self._endpoints = []
예제 #3
0
class PixelAddressRepeater(SimpleElaboratable):
    """Repeats addresses from PixelAddressGenerator.

    The systolic array requires multiple passes over input data. This class
    provides that functionatlity by repeating the pixel start addresses
    generated from PixelAddress Generator.

    Pixel addresses are repeated in groups of four, which matches the
    number of outputs of the InputFetcher and inputs to the systolic array.

    Attributes
    ----------

    repeats: Signal(unsigned_upto(64)), in
        The number of times each stream of input pixel data is to be repeated.

    next: Signal(), in
        Indicates current address has been used. Address will be updated on next
        cycle with next row address.

    addr: Signal(14), out
        Output address

    start: Signal(), in
        Starts address generation. Addr will be updated on next cycle.

    gen_next: Signal(), out
        Indicates that a new pixel address is required.

    gen_addr: Signal(14), in
        Input from the PixelAddressGenerator

    """

    def __init__(self):
        self.repeats = Signal(unsigned_upto(64))
        self.next = Signal()
        self.addr = Signal(14)
        self.start = Signal()
        self.gen_next = Signal()
        self.gen_addr = Signal(14)

    def elab(self, m):
        group = Signal(range(4))
        repeat_count = Signal.like(self.repeats)
        mem = Array([Signal(14, name=f"mem{i}") for i in range(4)])

        with m.If(repeat_count == 0):
            # On first repeat - pass through next and addr and record addresses
            m.d.comb += self.gen_next.eq(self.next)
            m.d.comb += self.addr.eq(self.gen_addr)
            with m.If(self.next):
                m.d.sync += mem[group].eq(self.gen_addr)
        with m.Else():
            # Subsequently use recorded data
            m.d.comb += self.addr.eq(mem[group])

        # Update group and repeat_count on next
        with m.If(self.next):
            m.d.sync += group.eq(group + 1)
            with m.If(group == 3):
                m.d.sync += repeat_count.eq(repeat_count + 1)
                with m.If(repeat_count + 1 == self.repeats):
                    m.d.sync += repeat_count.eq(0)

        with m.If(self.start):
            m.d.sync += repeat_count.eq(0)
            m.d.sync += group.eq(0)
예제 #4
0
 def __init__(self):
     self.a = Signal(signed(16))
     self.b = Signal(signed(16))
     self.c = Signal(signed(32))
예제 #5
0
class USBDevice(Elaboratable):
    """ Core gateware common to all LUNA USB2 devices.

    The ``USBDevice`` module contains the low-level communications hardware necessary to implement a USB device;
    including hardware for maintaining device state, detecting events, reading data from the host, and generating
    responses.

    This class can be instantiated directly, and used to build a USB device,
    or can be subclassed to create custom device types.

    To configure a ``USBDevice`` from a CPU or other wishbone master, see :class:`USBDeviceController`;
    which can easily be attached using its `attach` method.


    Parameters
    ----------

    bus: [UTMI interface, ULPI Interface]
        The UTMI or ULPI PHY connection to be used for communications.

    handle_clocking: bool, Optional
        True iff we should attempt to connect up the `usb` clock domain to the PHY
        automatically based on the clk signals's I/O direction. This option may not work
        for non-simple connections; in which case you will need to connect the clock signal
        yourself.


    Attributes
    ----------

    connect: Signal(), input
        Held high to keep the current USB device connected; or held low to disconnect.
    low_speed_only: Signal(), input
        If high, the device will operate at low speed.
    full_speed_only: Signal(), input
        If high, the device will be prohibited from operating at high speed.

    frame_number: Signal(11), output
        The current USB frame number.
    microframe_number: Signal(3), output
        The current USB microframe number. Always 0 on non-HS connections.
    sof_detected: Signal(), output
        Pulses for one cycle each time a SOF is detected; and thus our frame number has changed.
    new_frame: Signal(), output
        Strobe that indicates a new frame (not microframe) is detected.

    reset_detected: Signal(), output
        Asserted when the USB device receives a bus reset.

    # State signals.
    suspended: Signal(), output
        High when the device is in USB suspend. This can be (and by the spec must be) used to trigger
        the device to enter lower-power states.

    tx_activity_led: Signal(), output
        Signal that can be used to drive an activity LED for TX.
    rx_activity_led: Signal(), output
        Signal that can be used to drive an activity LED for RX.

    """
    def __init__(self, *, bus, handle_clocking=True):
        """
        Parameters:
        """

        # If this looks more like a ULPI bus than a UTMI bus, translate it.
        if hasattr(bus, 'dir'):
            self.utmi = UTMITranslator(ulpi=bus,
                                       handle_clocking=handle_clocking)
            self.bus_busy = self.utmi.busy
            self.translator = self.utmi
            self.always_fs = False
            self.data_clock = 60e6

        # If this looks more like raw I/O connections than a UTMI bus, create a pure-gatware
        # PHY to drive the raw I/O signals.
        elif hasattr(bus, 'd_n'):
            self.utmi = GatewarePHY(io=bus)
            self.bus_busy = Const(0)
            self.translator = self.utmi
            self.always_fs = True
            self.data_clock = 12e6

        # Otherwise, use it directly.
        # Note that since a true UTMI interface has separate Tx/Rx/control
        # interfaces, we don't need to care about bus 'busyness'; so we'll
        # set it to a const zero.
        else:
            self.utmi = bus
            self.bus_busy = Const(0)
            self.translator = None
            self.always_fs = True
            self.data_clock = 12e6

        #
        # I/O port
        #
        self.connect = Signal()
        self.low_speed_only = Signal()
        self.full_speed_only = Signal()

        self.frame_number = Signal(11)
        self.microframe_number = Signal(3)
        self.sof_detected = Signal()
        self.new_frame = Signal()
        self.reset_detected = Signal()

        self.speed = Signal(2)
        self.suspended = Signal()
        self.tx_activity_led = Signal()
        self.rx_activity_led = Signal()

        #
        # Internals.
        #
        self._endpoints = []

    def add_endpoint(self, endpoint):
        """ Adds an endpoint interface to the device.

        Parameters
        ----------
        endpoint: Elaborateable
            The endpoint interface to be added. Can be any piece of gateware with a
            :class:`EndpointInterface` attribute called ``interface``.
        """
        self._endpoints.append(endpoint)

    def add_control_endpoint(self):
        """ Adds a basic control endpoint to the device.

        Does not add any request handlers. If you want standard request handlers;
        :attr:`add_standard_control_endpoint` automatically adds standard request handlers.

        Returns
        -------
        Returns the endpoint object for the control endpoint.
        """
        control_endpoint = USBControlEndpoint(utmi=self.utmi)
        self.add_endpoint(control_endpoint)

        return control_endpoint

    def add_standard_control_endpoint(self,
                                      descriptors: DeviceDescriptorCollection,
                                      **kwargs):
        """ Adds a control endpoint with standard request handlers to the device.

        Parameters will be passed on to StandardRequestHandler.

        Return value
        ------------
        The endpoint object created.
        """

        # Create our endpoint, and add standard descriptors to it.
        control_endpoint = USBControlEndpoint(utmi=self.utmi)
        control_endpoint.add_standard_request_handlers(descriptors, **kwargs)
        self.add_endpoint(control_endpoint)

        return control_endpoint

    def elaborate(self, platform):
        m = Module()

        # If we have a bus translator, include it in our submodules.
        if self.translator:
            m.submodules.translator = self.translator

        #
        # Internal device state.
        #

        # Stores the device's current address. Used to identify which packets are for us.
        address = Signal(7, reset=0)

        # Stores the device's current configuration. Defaults to unconfigured.
        configuration = Signal(8, reset=0)

        #
        # Internal interconnections.
        #

        # Create our reset sequencer, which will be in charge of detecting USB port resets,
        # detecting high-speed hosts, and communicating that we are a high speed device.
        m.submodules.reset_sequencer = reset_sequencer = USBResetSequencer()

        m.d.comb += [
            reset_sequencer.bus_busy.eq(self.bus_busy),
            reset_sequencer.vbus_connected.eq(~self.utmi.session_end),
            reset_sequencer.line_state.eq(self.utmi.line_state),
        ]

        # Create our internal packet components:
        # - A token detector, which will identify and parse the tokens that start transactions.
        # - A data transmitter, which will transmit provided data streams.
        # - A data receiver, which will receive data from UTMI and convert it into streams.
        # - A handshake generator, which will assist in generating response packets.
        # - A handshake detector, which detects handshakes generated by the host.
        # - A data CRC16 handler, which will compute data packet CRCs.
        # - An interpacket delay timer, which will enforce interpacket delays.
        m.submodules.token_detector      = token_detector      = \
            USBTokenDetector(utmi=self.utmi, domain_clock=self.data_clock, fs_only=self.always_fs)
        m.submodules.transmitter = transmitter = USBDataPacketGenerator()
        m.submodules.receiver = receiver = USBDataPacketReceiver(
            utmi=self.utmi)
        m.submodules.handshake_generator = handshake_generator = USBHandshakeGenerator(
        )
        m.submodules.handshake_detector = handshake_detector = USBHandshakeDetector(
            utmi=self.utmi)
        m.submodules.data_crc = data_crc = USBDataPacketCRC()
        m.submodules.timer               = timer               = \
            USBInterpacketTimer(domain_clock=self.data_clock, fs_only=self.always_fs)

        # Connect our transmitter/receiver to our CRC generator.
        data_crc.add_interface(transmitter.crc)
        data_crc.add_interface(receiver.data_crc)

        # Connect our receiver to our timer.
        timer.add_interface(receiver.timer)

        m.d.comb += [
            # Ensure our token detector only responds to tokens addressed to us.
            token_detector.address.eq(address),

            # Hook up our data_crc to our receive inputs.
            data_crc.rx_data.eq(self.utmi.rx_data),
            data_crc.rx_valid.eq(self.utmi.rx_valid),

            # Connect our state signals to our subordinate components.
            token_detector.speed.eq(self.speed),
            timer.speed.eq(self.speed)
        ]

        #
        # Endpoint connections.
        #

        # Create our endpoint multiplexer...
        m.submodules.endpoint_mux = endpoint_mux = USBEndpointMultiplexer()
        endpoint_collection = endpoint_mux.shared

        # Connect our timer and CRC interfaces.
        timer.add_interface(endpoint_collection.timer)
        data_crc.add_interface(endpoint_collection.data_crc)

        m.d.comb += [
            # Low-level hardware interface.
            token_detector.interface.connect(endpoint_collection.tokenizer),
            handshake_detector.detected.connect(
                endpoint_collection.handshakes_in),

            # Device state.
            endpoint_collection.speed.eq(self.speed),
            endpoint_collection.active_config.eq(configuration),
            endpoint_collection.active_address.eq(address),

            # Receive interface.
            receiver.stream.connect(endpoint_collection.rx),
            endpoint_collection.rx_complete.eq(receiver.packet_complete),
            endpoint_collection.rx_invalid.eq(receiver.crc_mismatch),
            endpoint_collection.rx_ready_for_response.eq(
                receiver.ready_for_response),
            endpoint_collection.rx_pid_toggle.eq(receiver.active_pid[3]),

            # Transmit interface.
            endpoint_collection.tx.attach(transmitter.stream),
            handshake_generator.issue_ack.eq(
                endpoint_collection.handshakes_out.ack),
            handshake_generator.issue_nak.eq(
                endpoint_collection.handshakes_out.nak),
            handshake_generator.issue_stall.eq(
                endpoint_collection.handshakes_out.stall),
            transmitter.data_pid.eq(endpoint_collection.tx_pid_toggle),
        ]

        # If an endpoint wants to update our address or configuration, accept the update.
        with m.If(endpoint_collection.address_changed):
            m.d.usb += address.eq(endpoint_collection.new_address)
        with m.If(endpoint_collection.config_changed):
            m.d.usb += configuration.eq(endpoint_collection.new_config)

        # Finally, add each of our endpoints to this module and our multiplexer.
        for endpoint in self._endpoints:

            # Create a display name for the endpoint...
            name = endpoint.__class__.__name__
            if hasattr(m.submodules, name):
                name = f"{name}_{id(endpoint)}"

            # ... and add it, both as a submodule and to our multiplexer.
            endpoint_mux.add_interface(endpoint.interface)
            m.submodules[name] = endpoint

        #
        # Transmitter multiplexing.
        #

        # Create a multiplexer that will arbitrate access to the transmit lines.
        m.submodules.tx_multiplexer = tx_multiplexer = UTMIInterfaceMultiplexer(
        )

        # Connect each of our transmitters.
        tx_multiplexer.add_input(reset_sequencer.tx)
        tx_multiplexer.add_input(transmitter.tx)
        tx_multiplexer.add_input(handshake_generator.tx)

        m.d.comb += [
            # Connect our transmit multiplexer to the actual UTMI bus.
            tx_multiplexer.output.attach(self.utmi),

            # Connect up the transmit CRC interface to our UTMI bus.
            data_crc.tx_valid.eq(tx_multiplexer.output.valid
                                 & self.utmi.tx_ready),
            data_crc.tx_data.eq(tx_multiplexer.output.data),
        ]

        #
        # Device-state management.
        #

        # On a bus reset, clear our address and configuration.
        with m.If(reset_sequencer.bus_reset):
            m.d.usb += [
                address.eq(0),
                configuration.eq(0),
            ]

        # Device operating state controls.
        m.d.comb += [
            # Disable our host-mode pulldowns; as we're a device.
            self.utmi.dm_pulldown.eq(0),
            self.utmi.dp_pulldown.eq(0),

            # Let our reset sequencer set our USB mode and speed.
            reset_sequencer.low_speed_only.eq(self.low_speed_only
                                              & ~self.always_fs),
            reset_sequencer.full_speed_only.eq(self.full_speed_only
                                               | self.always_fs),
            self.utmi.op_mode.eq(reset_sequencer.operating_mode),
            self.utmi.xcvr_select.eq(reset_sequencer.current_speed),
            self.utmi.term_select.eq(reset_sequencer.termination_select
                                     & self.connect),
        ]

        #
        # Frame/microframe state.
        #

        # Handle each new SOF token as we receive them.
        with m.If(token_detector.interface.new_frame):

            # Update our knowledge of the current frame number.
            m.d.usb += self.frame_number.eq(token_detector.interface.frame)

            # Check if we're receiving a new 1ms frame -- which occurs when the new SOF's
            # frame number is different from the previous one's. This will always be the case
            # on full speed links; and will be the case 1/8th of the time on High Speed links.
            m.d.comb += self.new_frame.eq(
                token_detector.interface.frame != self.frame_number)

            # If this is a new frame, our microframe count should be zero.
            with m.If(self.new_frame):
                m.d.usb += self.microframe_number.eq(0)

            # Otherwise, this SOF indicates a new _microframe_ [USB 2.0: 8.4.3.1].
            with m.Else():
                m.d.usb += self.microframe_number.eq(self.microframe_number +
                                                     1)

        #
        # Device-state outputs.
        #
        m.d.comb += [
            self.speed.eq(reset_sequencer.current_speed),
            self.suspended.eq(reset_sequencer.suspended),
            self.sof_detected.eq(token_detector.interface.new_frame),
            self.reset_detected.eq(reset_sequencer.bus_reset),
            self.tx_activity_led.eq(tx_multiplexer.output.valid),
            self.rx_activity_led.eq(self.utmi.rx_valid)
        ]

        return m
예제 #6
0
class TxShifter(Elaboratable):
    """Transmit Shifter

    TxShifter accepts parallel data and shifts it out serially.

    Parameters
    ----------
    Parameters are passed in via the constructor.

    width : int
        Width of the data to be shifted.

    Input Ports
    -----------
    Input ports are passed in via the constructor.

    i_data: Signal(width)
        Data to be transmitted.

    i_enable: Signal(), input
        When asserted, shifting will be allowed; otherwise, the shifter will be stalled.

    Output Ports
    ------------
    Output ports are data members of the module. All outputs are flopped.

    o_data : Signal()
        Serial data output.

    o_empty : Signal()
        Asserted the cycle before the shifter loads in more i_data.

    o_get : Signal()
        Asserted the cycle after the shifter loads in i_data.

    """
    def __init__(self, width):
        self._width = width

        #
        # I/O Port
        #
        self.i_data = Signal(width)
        self.i_enable = Signal()
        self.i_clear = Signal()

        self.o_get = Signal()
        self.o_empty = Signal()

        self.o_data = Signal()

    def elaborate(self, platform):
        m = Module()

        shifter = Signal(self._width)
        pos = Signal(self._width, reset=0b1)

        with m.If(self.i_enable):
            empty = Signal()
            m.d.usb += [
                pos.eq(pos >> 1),
                shifter.eq(shifter >> 1),
                self.o_get.eq(empty),
            ]

            with m.If(empty):
                m.d.usb += [
                    shifter.eq(self.i_data),
                    pos.eq(1 << (self._width - 1)),
                ]

        with m.If(self.i_clear):
            m.d.usb += [shifter.eq(0), pos.eq(1)]

        m.d.comb += [
            empty.eq(pos[0]),
            self.o_empty.eq(empty),
            self.o_data.eq(shifter[0]),
        ]

        return m
예제 #7
0
class Polynomal(Elaboratable):
    """ Sets motor states using a polynomal algorithm

        A polynomal up to 3 order, i.e. c*t^3+b*t^2+a*t,
        is evaluated under the assumption that t starts at 0
        and has a maximum of say 10_000 ticks.
        The polynomal describes the stepper position of a single axis.
        A counter is used to capture the state of the polynomal.
        If a given bit, denoted by bitshift, of the counter changes,
        a step is sent to the motor.
        In every tick the step can at most increase
        with one count.
        Non step part of base Counters are kept after segment.
        Higher orders, velocity etc are removed.

        This code requires a lot of LUT, only order 2 is supported on UP5k
        It is assumed that the user can completely determine
        the outcome of the calculation.
        To ascertain step accuracy, c is submitted with a very high accuracy.
        For third order, this requires 41 bit wide numbers
        and is a "weakness" in the code.
        The code might be sped up via Horner's method and the use of DSPs.
        The current code does not require a DSP.

        Assumptions:
        max ticks per move is 10_000
        update frequency motor is 1 MHz

        I/O signals:
        I: coeff          -- polynomal coefficients
        I: start          -- start signal
        O: busy           -- busy signal
        O: finished       -- finished signal
        O: total steps    -- total steps executed in move
        O: dir            -- direction; 1 is postive and 0 is negative
        O: step           -- step signal
    """
    def __init__(self, platform=None, top=False):
        '''
            platform  -- pass test platform
            top       -- trigger synthesis of module
        '''
        self.top = top
        self.platform = platform
        self.divider = platform.clks[platform.hfosc_div]
        self.order = platform.poldegree
        self.bit_shift = bit_shift(platform)
        self.motors = platform.motors
        self.max_steps = int(MOVE_TICKS / 2)  # Nyquist
        # inputs
        self.coeff = Array()
        for _ in range(self.motors):
            self.coeff.extend([
                Signal(signed(self.bit_shift + 1)),
                Signal(signed(self.bit_shift + 1)),
                Signal(signed(self.bit_shift + 1))
            ][:self.order])
        self.start = Signal()
        self.ticklimit = Signal(MOVE_TICKS.bit_length())
        # output
        self.busy = Signal()
        self.dir = Array(Signal() for _ in range(self.motors))
        self.step = Array(Signal() for _ in range(self.motors))

    def elaborate(self, platform):
        m = Module()
        # add 1 MHz clock domain
        cntr = Signal(range(self.divider))
        # pos
        max_bits = (self.max_steps << self.bit_shift).bit_length()
        cntrs = Array(
            Signal(signed(max_bits + 1)) for _ in range(len(self.coeff)))
        assert max_bits <= 64
        ticks = Signal(MOVE_TICKS.bit_length())
        if self.top:
            steppers = [res for res in get_all_resources(platform, "stepper")]
            assert len(steppers) != 0
            for idx, stepper in enumerate(steppers):
                m.d.comb += [
                    stepper.step.eq(self.step[idx]),
                    stepper.dir.eq(self.dir[idx])
                ]
        else:
            self.ticks = ticks
            self.cntrs = cntrs

        # steps
        for motor in range(self.motors):
            m.d.comb += self.step[motor].eq(cntrs[motor *
                                                  self.order][self.bit_shift])

        # directions
        counter_d = Array(
            Signal(signed(max_bits + 1)) for _ in range(self.motors))
        for motor in range(self.motors):
            m.d.sync += counter_d[motor].eq(cntrs[motor * self.order])
            # negative case --> decreasing
            with m.If(counter_d[motor] > cntrs[motor * self.order]):
                m.d.sync += self.dir[motor].eq(0)
            # positive case --> increasing
            with m.Elif(counter_d[motor] < cntrs[motor * self.order]):
                m.d.sync += self.dir[motor].eq(1)
        with m.FSM(reset='RESET', name='polynomen'):
            with m.State('RESET'):
                m.next = 'WAIT_START'

                m.d.sync += self.busy.eq(0)
            with m.State('WAIT_START'):
                with m.If(self.start):
                    for motor in range(self.motors):
                        coef0 = motor * self.order
                        step_bit = self.bit_shift + 1
                        m.d.sync += [
                            cntrs[coef0].eq(cntrs[coef0][:step_bit]),
                            counter_d[motor].eq(counter_d[motor][:step_bit])
                        ]
                        for degree in range(1, self.order):
                            m.d.sync += cntrs[coef0 + degree].eq(0)
                    m.d.sync += self.busy.eq(1)
                    m.next = 'RUNNING'
                with m.Else():
                    m.d.sync += self.busy.eq(0)
            with m.State('RUNNING'):
                with m.If((ticks < self.ticklimit)
                          & (cntr >= self.divider - 1)):
                    m.d.sync += [ticks.eq(ticks + 1), cntr.eq(0)]
                    for motor in range(self.motors):
                        order = self.order
                        idx = motor * order
                        op3, op2, op1 = 0, 0, 0
                        if order > 2:
                            op3 += 3 * 2 * self.coeff[idx + 2] + cntrs[idx + 2]
                            op2 += cntrs[idx + 2]
                            op1 += self.coeff[idx + 2] + cntrs[idx + 2]
                            m.d.sync += cntrs[idx + 2].eq(op3)
                        if order > 1:
                            op2 += (2 * self.coeff[idx + 1] + cntrs[idx + 1])
                            m.d.sync += cntrs[idx + 1].eq(op2)
                        op1 += (self.coeff[idx + 1] + self.coeff[idx] +
                                cntrs[idx + 1] + cntrs[idx])
                        m.d.sync += cntrs[idx].eq(op1)
                with m.Elif(ticks < self.ticklimit):
                    m.d.sync += cntr.eq(cntr + 1)
                with m.Else():
                    m.d.sync += ticks.eq(0)
                    m.next = 'WAIT_START'
        return m
예제 #8
0
class PostProcessor(SimpleElaboratable):
    """Does post-processing of an accumulator value.

    This is a pipeline: place values at inputs and outputs appear 4 cycles later.
    It is capable of producing one result per cycle.

    The function being implemented is:

    acc += param_store_read(&output_bias);
    acc = cpp_math_mul_by_quantized_mul_software(
        acc, param_store_read(&output_multiplier),
        param_store_read(&output_shift));
    acc += reg_output_offset;
    if (acc < reg_activation_min) {
        acc = reg_activation_min;
    } else if (acc > reg_activation_max) {
        acc = reg_activation_max;
    }
    return acc;

    Attributes
    ---------
    accumulator: Signal(signed(32)) input
      The accumulator value to be post processed
    bias: Signal(signed(32)) input
      Bias to add to accumulator
    multiplier: Signal(signed(32)) input
      output multiplier to apply
    shift: Signal(signed(32)) input
      shift to apply (negative for right shift)
    offset: Signal(signed(32)) input
      amount to transform output by before clamping
    activation_min: Signal(signed(32)) input
      minimum clamp for output
    activation_max: Signal(signed(32)) input
      maximum clamp for output
    result: Signal(signed(32)) output
      The post processed result
    """

    # TODO: see if we can make this 3 cycles by bringing SRDHM down to 2 cycles
    PIPELINE_CYCLES = 4

    def __init__(self):
        self.accumulator = Signal(signed(32))
        self.bias = Signal(signed(32))
        self.multiplier = Signal(signed(32))
        self.shift = Signal(signed(32))
        self.offset = Signal(signed(32))
        self.activation_min = Signal(signed(32))
        self.activation_max = Signal(signed(32))
        self.result = Signal(signed(32))

    def elab(self, m):
        with_bias = Signal(signed(32))
        m.d.comb += with_bias.eq(self.accumulator + self.bias)

        # acc = cpp_math_mul_by_quantized_mul_software(
        #       acc, param_store_read(&output_multiplier),
        #       param_store_read(&output_shift));
        left_shift = Signal(5)
        right_sr = [Signal(5, name=f'right_sr_{n}') for n in range(4)]
        with m.If(self.shift > 0):
            m.d.comb += left_shift.eq(self.shift)
        with m.Else():
            m.d.comb += right_sr[0].eq(-self.shift)
        left_shifted = Signal(32)
        m.d.comb += left_shifted.eq(with_bias << left_shift),

        # Pass right shift value down through several cycles to where
        # it is needed
        for a, b in zip(right_sr, right_sr[1:]):
            m.d.sync += b.eq(a)

        # All logic is combinational up to the inputs to the SRDHM
        m.submodules['srdhm'] = srdhm = SRDHM()
        m.d.comb += [
            srdhm.a.eq(left_shifted),
            srdhm.b.eq(self.multiplier),
        ]

        # Output from SRDHM appears several cycles later
        right_shifted = Signal(signed(32))
        m.d.sync += right_shifted.eq(
            rounding_divide_by_pot(srdhm.result, right_sr[-1]))

        # This logic is combinational to output
        # acc += reg_output_offset
        # if (acc < reg_activation_min) {
        #     acc = reg_activation_min
        # } else if (acc > reg_activation_max) {
        #     acc = reg_activation_max
        # }
        # return acc
        with_offset = Signal(signed(32))
        m.d.comb += [
            with_offset.eq(right_shifted + self.offset),
            self.result.eq(
                clamped(with_offset, self.activation_min,
                        self.activation_max)),
        ]
예제 #9
0
    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
예제 #10
0
 def __init__(self):
     super().__init__()
     self.bias = Signal(signed(32))
     self.bias_next = Signal()
     self.multiplier = Signal(signed(32))
     self.multiplier_next = Signal()
     self.shift = Signal(signed(32))
     self.shift_next = Signal()
     self.offset = Signal(signed(32))
     self.activation_min = Signal(signed(32))
     self.activation_max = Signal(signed(32))
예제 #11
0
 def __init__(self):
     self.a = Signal(signed(32))
     self.b = Signal(signed(32))
     self.result = Signal(signed(32))
예제 #12
0
class PostProcessXetter(Xetter):
    """Does post-processing of an accumulator value.

    The output channel index is implied by processing order. This
    is mostly a wrapper around PostProcessor.

    Attributes
    ---------
    bias: Signal(signed(32)) input
      output_bias from param store
    bias_next: Signal() output
      signal that output_bias has been read
    multiplier: Signal(signed(32)) input
      output_multiplier from param store
    multiplier_next: Signal() output
      signal that output_multiplier has been read
    shift: Signal(signed(32)) input
      output_shift from param store
    shift_next: Signal() output
      signal that output_shift has been read
    offset: Signal(signed(32)) input
      amount to transform output by before clamping
    activation_min: Signal(signed(32)) input
      minimum clamp for output
    activation_max: Signal(signed(32)) input
      maximum clamp for output
    """
    def __init__(self):
        super().__init__()
        self.bias = Signal(signed(32))
        self.bias_next = Signal()
        self.multiplier = Signal(signed(32))
        self.multiplier_next = Signal()
        self.shift = Signal(signed(32))
        self.shift_next = Signal()
        self.offset = Signal(signed(32))
        self.activation_min = Signal(signed(32))
        self.activation_max = Signal(signed(32))

    def elab(self, m):
        m.submodules['pp'] = pp = PostProcessor()

        # Connections to post processor
        m.d.comb += [
            pp.accumulator.eq(self.in0.as_signed()),
            pp.bias.eq(self.bias),
            pp.multiplier.eq(self.multiplier),
            pp.shift.eq(self.shift),
            pp.offset.eq(self.offset),
            pp.activation_min.eq(self.activation_min),
            pp.activation_max.eq(self.activation_max),
            self.output.eq(pp.result),
        ]

        # Use a sequencer to count down to processing end
        m.submodules['delay'] = delay = Delayer(PostProcessor.PIPELINE_CYCLES)
        m.d.comb += delay.input.eq(self.start)

        # Other control signal outputs - set *_next to indicate values used
        # Set done to fire when calculation is complete
        m.d.comb += [
            self.bias_next.eq(self.start),
            self.multiplier_next.eq(self.start),
            self.shift_next.eq(self.start),
            self.done.eq(delay.output),
        ]
예제 #13
0
    def elab(self, m):
        with_bias = Signal(signed(32))
        m.d.comb += with_bias.eq(self.accumulator + self.bias)

        # acc = cpp_math_mul_by_quantized_mul_software(
        #       acc, param_store_read(&output_multiplier),
        #       param_store_read(&output_shift));
        left_shift = Signal(5)
        right_sr = [Signal(5, name=f'right_sr_{n}') for n in range(4)]
        with m.If(self.shift > 0):
            m.d.comb += left_shift.eq(self.shift)
        with m.Else():
            m.d.comb += right_sr[0].eq(-self.shift)
        left_shifted = Signal(32)
        m.d.comb += left_shifted.eq(with_bias << left_shift),

        # Pass right shift value down through several cycles to where
        # it is needed
        for a, b in zip(right_sr, right_sr[1:]):
            m.d.sync += b.eq(a)

        # All logic is combinational up to the inputs to the SRDHM
        m.submodules['srdhm'] = srdhm = SRDHM()
        m.d.comb += [
            srdhm.a.eq(left_shifted),
            srdhm.b.eq(self.multiplier),
        ]

        # Output from SRDHM appears several cycles later
        right_shifted = Signal(signed(32))
        m.d.sync += right_shifted.eq(
            rounding_divide_by_pot(srdhm.result, right_sr[-1]))

        # This logic is combinational to output
        # acc += reg_output_offset
        # if (acc < reg_activation_min) {
        #     acc = reg_activation_min
        # } else if (acc > reg_activation_max) {
        #     acc = reg_activation_max
        # }
        # return acc
        with_offset = Signal(signed(32))
        m.d.comb += [
            with_offset.eq(right_shifted + self.offset),
            self.result.eq(
                clamped(with_offset, self.activation_min,
                        self.activation_max)),
        ]
예제 #14
0
class SetInstruction(InstructionBase):
    """Handles sending values from CPU to CFU

    Attributes
    ----------

    reg_verify_value: Signal(32), out
       The value last set into the verify register

    accelerator_start: Signal(), out
       Toggles when start register written

    accelerator_reset: Signal(), out
       Toggles when reset register written

    config: Record(ACCELERATOR_CONFIGURATION_LAYOUT), out
       Configuration values for accelerator core, as received
       from set instructions.

    filter_output: Endpoint(FILTER_WRITE_COMMAND), out
        Write command for filter store

    post_process_params: Endpoint(POST_PROCESS_PARAMS), out
        Stream of data to write to post_process memory.
    """

    def __init__(self):
        super().__init__()
        self.reg_verify_value = Signal(32)
        self.accelerator_start = Signal()
        self.accelerator_reset = Signal()
        self.config = Record(ACCELERATOR_CONFIGURATION_LAYOUT)
        self.filter_output = Endpoint(FILTER_WRITE_COMMAND)
        self.post_process_params = Endpoint(POST_PROCESS_PARAMS)

    def elab(self, m):
        # Default toggles to off
        m.d.sync += self.accelerator_start.eq(0)
        m.d.sync += self.accelerator_reset.eq(0)
        m.d.sync += self.filter_output.valid.eq(0)
        m.d.sync += self.post_process_params.valid.eq(0)

        # All sets take exactly one cycle
        m.d.sync += self.done.eq(0)

        # Perform action
        with m.If(self.start):
            with m.Switch(self.funct7):
                with m.Case(Constants.REG_VERIFY):
                    m.d.sync += self.reg_verify_value.eq(self.in0)
                with m.Case(Constants.REG_ACCELERATOR_START):
                    m.d.sync += self.accelerator_start.eq(1)
                with m.Case(Constants.REG_ACCELERATOR_RESET):
                    m.d.sync += self.accelerator_reset.eq(1)
                with m.Case(Constants.REG_FILTER_WRITE):
                    m.d.sync += [
                        self.filter_output.payload.store.eq(self.in0[16:]),
                        self.filter_output.payload.addr.eq(self.in0[:16]),
                        self.filter_output.payload.data.eq(self.in1),
                        self.filter_output.valid.eq(1),
                    ]
                with m.Case(Constants.REG_MODE):
                    m.d.sync += self.config.mode.eq(self.in0)
                with m.Case(Constants.REG_INPUT_OFFSET):
                    m.d.sync += self.config.input_offset.eq(self.in0s)
                with m.Case(Constants.REG_NUM_FILTER_WORDS):
                    m.d.sync += self.config.num_filter_words.eq(self.in0)
                with m.Case(Constants.REG_OUTPUT_OFFSET):
                    m.d.sync += self.config.output_offset.eq(self.in0s)
                with m.Case(Constants.REG_OUTPUT_ACTIVATION_MIN):
                    m.d.sync += self.config.output_activation_min.eq(self.in0s)
                with m.Case(Constants.REG_OUTPUT_ACTIVATION_MAX):
                    m.d.sync += self.config.output_activation_max.eq(self.in0s)
                with m.Case(Constants.REG_INPUT_BASE_ADDR):
                    m.d.sync += self.config.input_base_addr.eq(self.in0)
                with m.Case(Constants.REG_NUM_PIXELS_X):
                    m.d.sync += self.config.num_pixels_x.eq(self.in0)
                with m.Case(Constants.REG_PIXEL_ADVANCE_X):
                    m.d.sync += self.config.pixel_advance_x.eq(self.in0)
                with m.Case(Constants.REG_PIXEL_ADVANCE_Y):
                    m.d.sync += self.config.pixel_advance_y.eq(self.in0)
                with m.Case(Constants.REG_INPUT_CHANNEL_DEPTH):
                    m.d.sync += self.config.input_channel_depth.eq(self.in0)
                with m.Case(Constants.REG_OUTPUT_CHANNEL_DEPTH):
                    m.d.sync += self.config.output_channel_depth.eq(self.in0)
                with m.Case(Constants.REG_NUM_OUTPUT_VALUES):
                    m.d.sync += self.config.num_output_values.eq(self.in0)
                with m.Case(Constants.REG_POST_PROCESS_BIAS):
                    m.d.sync += self.post_process_params.payload.bias.eq(
                        self.in0s)
                with m.Case(Constants.REG_POST_PROCESS_SHIFT):
                    m.d.sync += self.post_process_params.payload.shift.eq(
                        self.in0)
                with m.Case(Constants.REG_POST_PROCESS_MULTIPLIER):
                    m.d.sync += [
                        self.post_process_params.payload.multiplier.eq(
                            self.in0s),
                        self.post_process_params.valid.eq(1),
                    ]
            m.d.sync += self.done.eq(1)
예제 #15
0
    def __init__(self):
        self.i_bit_strobe = Signal()

        self.i_data_payload = Signal(8)
        self.o_data_strobe = Signal()

        self.i_oe = Signal()

        self.o_usbp = Signal()
        self.o_usbn = Signal()
        self.o_oe = Signal()

        self.o_pkt_end = Signal()

        self.fit_dat = Signal()
        self.fit_oe = Signal()
예제 #16
0
class SPIParser(Elaboratable):
    """ Parses and replies to commands over SPI

    The following commmands are possible
      status -- send back state of the peripheriral
      start  -- enables parsing of FIFO
      stop   -- halts parsing of FIFO
      write  -- write instruction to FIFO or report memory is full

    I/O signals:
        I/O: Spibus       -- spi bus connected to peripheral
        I: positions      -- positions of stepper motors
        I: pin state      -- used to get the value of select pins at client
        I: read_commit    -- finalize read transactionalizedfifo
        I: read_en        -- enable read transactionalizedfifo
        I: read_discard   -- read discard of transactionalizedfifo
        I: dispatcherror  -- error while processing stored command from spi
        O: execute        -- start processing gcode
        O: read_data      -- read data from transactionalizedfifo
        O: empty          -- transactionalizedfifo is empty
    """
    def __init__(self, platform, top=False):
        """
        platform  -- pass test platform
        top       -- trigger synthesis of module
        """
        self.platform = platform
        self.top = top

        self.spi = SPIBus()
        self.position = Array(
            Signal(signed(64)) for _ in range(platform.motors))
        self.pinstate = Signal(8)
        self.read_commit = Signal()
        self.read_en = Signal()
        self.read_discard = Signal()
        self.dispatcherror = Signal()
        self.parse = Signal()
        self.read_data = Signal(MEMWIDTH)
        self.empty = Signal()

    def elaborate(self, platform):
        m = Module()
        if platform and self.top:
            board_spi = platform.request("debug_spi")
            spi2 = synchronize(m, board_spi)
            m.d.comb += self.spi.connect(spi2)
        if self.platform:
            platform = self.platform
        spi = self.spi
        interf = SPICommandInterface(command_size=COMMAND_BYTES * 8,
                                     word_size=WORD_BYTES * 8)
        m.d.comb += interf.spi.connect(spi)
        m.submodules.interf = interf
        # FIFO connection
        fifo = TransactionalizedFIFO(width=MEMWIDTH, depth=platform.memdepth)
        if platform.name == 'Test':
            self.fifo = fifo
        m.submodules.fifo = fifo
        m.d.comb += [
            self.read_data.eq(fifo.read_data),
            fifo.read_commit.eq(self.read_commit),
            fifo.read_discard.eq(self.read_discard),
            fifo.read_en.eq(self.read_en),
            self.empty.eq(fifo.empty)
        ]
        # Parser
        mtrcntr = Signal(range(platform.motors))
        wordsreceived = Signal(range(wordsinmove(platform) + 1))
        error = Signal()
        # Peripheral state
        state = Signal(8)
        m.d.sync += [
            state[STATE.PARSING].eq(self.parse),
            state[STATE.FULL].eq(fifo.space_available <= 1),
            state[STATE.ERROR].eq(self.dispatcherror | error)
        ]
        # remember which word we are processing
        instruction = Signal(8)
        with m.FSM(reset='RESET', name='parser'):
            with m.State('RESET'):
                m.d.sync += [
                    self.parse.eq(1),
                    wordsreceived.eq(0),
                    error.eq(0)
                ]
                m.next = 'WAIT_COMMAND'
            with m.State('WAIT_COMMAND'):
                with m.If(interf.command_ready):
                    word = Cat(state[::-1], self.pinstate[::-1])
                    with m.If(interf.command == COMMANDS.EMPTY):
                        m.next = 'WAIT_COMMAND'
                    with m.Elif(interf.command == COMMANDS.START):
                        m.next = 'WAIT_COMMAND'
                        m.d.sync += self.parse.eq(1)
                    with m.Elif(interf.command == COMMANDS.STOP):
                        m.next = 'WAIT_COMMAND'
                        m.d.sync += self.parse.eq(0)
                    with m.Elif(interf.command == COMMANDS.WRITE):
                        m.d.sync += interf.word_to_send.eq(word)
                        with m.If(state[STATE.FULL] == 0):
                            m.next = 'WAIT_WORD'
                        with m.Else():
                            m.next = 'WAIT_COMMAND'
                    with m.Elif(interf.command == COMMANDS.READ):
                        m.d.sync += interf.word_to_send.eq(word)
                        m.next = 'WAIT_COMMAND'
                    with m.Elif(interf.command == COMMANDS.POSITION):
                        # position is requested multiple times for multiple
                        # motors
                        with m.If(mtrcntr < platform.motors - 1):
                            m.d.sync += mtrcntr.eq(mtrcntr + 1)
                        with m.Else():
                            m.d.sync += mtrcntr.eq(0)
                        m.d.sync += interf.word_to_send.eq(
                            self.position[mtrcntr])
                        m.next = 'WAIT_COMMAND'
            with m.State('WAIT_WORD'):
                with m.If(interf.word_complete):
                    byte0 = interf.word_received[:8]
                    with m.If(wordsreceived == 0):
                        with m.If((byte0 > 0) & (byte0 < 6)):
                            m.d.sync += [
                                instruction.eq(byte0),
                                fifo.write_en.eq(1),
                                wordsreceived.eq(wordsreceived + 1),
                                fifo.write_data.eq(interf.word_received)
                            ]
                            m.next = 'WRITE'
                        with m.Else():
                            m.d.sync += error.eq(1)
                            m.next = 'WAIT_COMMAND'
                    with m.Else():
                        m.d.sync += [
                            fifo.write_en.eq(1),
                            wordsreceived.eq(wordsreceived + 1),
                            fifo.write_data.eq(interf.word_received)
                        ]
                        m.next = 'WRITE'
            with m.State('WRITE'):
                m.d.sync += fifo.write_en.eq(0)
                wordslaser = wordsinscanline(
                    params(platform)['BITSINSCANLINE'])
                wordsmotor = wordsinmove(platform)
                with m.If(((instruction == INSTRUCTIONS.MOVE)
                           & (wordsreceived >= wordsmotor))
                          | (instruction == INSTRUCTIONS.WRITEPIN)
                          | (instruction == INSTRUCTIONS.LASTSCANLINE)
                          | ((instruction == INSTRUCTIONS.SCANLINE)
                             & (wordsreceived >= wordslaser))):
                    m.d.sync += [wordsreceived.eq(0), fifo.write_commit.eq(1)]
                    m.next = 'COMMIT'
                with m.Else():
                    m.next = 'WAIT_COMMAND'
            with m.State('COMMIT'):
                m.d.sync += fifo.write_commit.eq(0)
                m.next = 'WAIT_COMMAND'
        return m
예제 #17
0
    def elaborate(self, platform):
        m = Module()

        sync_pulse = Signal(8)

        da_reset_shifter = Signal()
        da_reset_bitstuff = Signal(
        )  # Need to reset the bit stuffer 1 cycle after the shifter.
        stall = Signal()

        # These signals are set during the sync pulse
        sp_reset_bitstuff = Signal()
        sp_reset_shifter = Signal()
        sp_bit = Signal()
        sp_o_data_strobe = Signal()

        # 12MHz domain
        bitstuff_valid_data = Signal()

        # Keep a Gray counter around to smoothly transition between states
        state_gray = Signal(2)
        state_data = Signal()
        state_sync = Signal()

        #
        # Transmit gearing.
        #
        m.submodules.shifter = shifter = TxShifter(width=8)
        m.d.comb += [
            shifter.i_data.eq(self.i_data_payload),
            shifter.i_enable.eq(~stall),
            shifter.i_clear.eq(da_reset_shifter | sp_reset_shifter)
        ]

        #
        # Bit-stuffing and NRZI.
        #
        bitstuff = ResetInserter(da_reset_bitstuff)(TxBitstuffer())
        m.submodules.bitstuff = bitstuff

        m.submodules.nrzi = nrzi = TxNRZIEncoder()

        #
        # Transmit controller.
        #

        m.d.comb += [
            # Send a data strobe when we're two bits from the end of the sync pulse.
            # This is because the pipeline takes two bit times, and we want to ensure the pipeline
            # has spooled up enough by the time we're there.
            bitstuff.i_data.eq(shifter.o_data),
            stall.eq(bitstuff.o_stall),
            sp_bit.eq(sync_pulse[0]),
            sp_reset_bitstuff.eq(sync_pulse[0]),

            # The shifter has one clock cycle of latency, so reset it
            # one cycle before the end of the sync byte.
            sp_reset_shifter.eq(sync_pulse[1]),
            sp_o_data_strobe.eq(sync_pulse[5]),
            state_data.eq(state_gray[0] & state_gray[1]),
            state_sync.eq(state_gray[0] & ~state_gray[1]),
            self.fit_oe.eq(state_data | state_sync),
            self.fit_dat.eq((state_data & shifter.o_data & ~bitstuff.o_stall)
                            | sp_bit),
            self.o_data_strobe.eq(state_data & shifter.o_get & ~stall
                                  & self.i_oe),
        ]

        # If we reset the shifter, then o_empty will go high on the next cycle.
        #

        m.d.usb += [
            # If the shifter runs out of data, percolate the "reset" signal to the
            # shifter, and then down to the bitstuffer.
            # da_reset_shifter.eq(~stall & shifter.o_empty & ~da_stalled_reset),
            # da_stalled_reset.eq(da_reset_shifter),
            # da_reset_bitstuff.eq(~stall & da_reset_shifter),
            bitstuff_valid_data.eq(~stall & shifter.o_get & self.i_oe),
        ]

        with m.FSM(domain="usb"):

            with m.State('IDLE'):
                with m.If(self.i_oe):
                    m.d.usb += [sync_pulse.eq(1 << 7), state_gray.eq(0b01)]
                    m.next = "SEND_SYNC"
                with m.Else():
                    m.d.usb += state_gray.eq(0b00)

            with m.State('SEND_SYNC'):
                m.d.usb += sync_pulse.eq(sync_pulse >> 1)

                with m.If(sync_pulse[0]):
                    m.d.usb += state_gray.eq(0b11)
                    m.next = "SEND_DATA"
                with m.Else():
                    m.d.usb += state_gray.eq(0b01)

            with m.State('SEND_DATA'):
                with m.If(~self.i_oe & shifter.o_empty & ~bitstuff.o_stall):
                    with m.If(bitstuff.o_will_stall):
                        m.next = 'STUFF_LAST_BIT'
                    with m.Else():
                        m.d.usb += state_gray.eq(0b10)
                        m.next = 'IDLE'

                with m.Else():
                    m.d.usb += state_gray.eq(0b11)

            with m.State('STUFF_LAST_BIT'):
                m.d.usb += state_gray.eq(0b10)
                m.next = 'IDLE'

        # 48MHz domain
        # NRZI encoding
        nrzi_dat = Signal()
        nrzi_oe = Signal()

        # Cross the data from the 12MHz domain to the 48MHz domain
        cdc_dat = FFSynchronizer(self.fit_dat,
                                 nrzi_dat,
                                 o_domain="usb_io",
                                 stages=3)
        cdc_oe = FFSynchronizer(self.fit_oe,
                                nrzi_oe,
                                o_domain="usb_io",
                                stages=3)
        m.submodules += [cdc_dat, cdc_oe]

        m.d.comb += [
            nrzi.i_valid.eq(self.i_bit_strobe),
            nrzi.i_data.eq(nrzi_dat),
            nrzi.i_oe.eq(nrzi_oe),
            self.o_usbp.eq(nrzi.o_usbp),
            self.o_usbn.eq(nrzi.o_usbn),
            self.o_oe.eq(nrzi.o_oe),
        ]

        return m
예제 #18
0
    def __init__(self, platform, top=False):
        """
        platform  -- pass test platform
        top       -- trigger synthesis of module
        """
        self.platform = platform
        self.top = top

        self.spi = SPIBus()
        self.position = Array(
            Signal(signed(64)) for _ in range(platform.motors))
        self.pinstate = Signal(8)
        self.read_commit = Signal()
        self.read_en = Signal()
        self.read_discard = Signal()
        self.dispatcherror = Signal()
        self.parse = Signal()
        self.read_data = Signal(MEMWIDTH)
        self.empty = Signal()
예제 #19
0
    def elaborate(self, platform):
        m = Module()

        shifter = Signal(self._width)
        pos = Signal(self._width, reset=0b1)

        with m.If(self.i_enable):
            empty = Signal()
            m.d.usb += [
                pos.eq(pos >> 1),
                shifter.eq(shifter >> 1),
                self.o_get.eq(empty),
            ]

            with m.If(empty):
                m.d.usb += [
                    shifter.eq(self.i_data),
                    pos.eq(1 << (self._width - 1)),
                ]

        with m.If(self.i_clear):
            m.d.usb += [shifter.eq(0), pos.eq(1)]

        m.d.comb += [
            empty.eq(pos[0]),
            self.o_empty.eq(empty),
            self.o_data.eq(shifter[0]),
        ]

        return m
예제 #20
0
 def elaborate(self, platform):
     m = Module()
     if platform and self.top:
         board_spi = platform.request("debug_spi")
         spi2 = synchronize(m, board_spi)
         m.d.comb += self.spi.connect(spi2)
     if self.platform:
         platform = self.platform
     spi = self.spi
     interf = SPICommandInterface(command_size=COMMAND_BYTES * 8,
                                  word_size=WORD_BYTES * 8)
     m.d.comb += interf.spi.connect(spi)
     m.submodules.interf = interf
     # FIFO connection
     fifo = TransactionalizedFIFO(width=MEMWIDTH, depth=platform.memdepth)
     if platform.name == 'Test':
         self.fifo = fifo
     m.submodules.fifo = fifo
     m.d.comb += [
         self.read_data.eq(fifo.read_data),
         fifo.read_commit.eq(self.read_commit),
         fifo.read_discard.eq(self.read_discard),
         fifo.read_en.eq(self.read_en),
         self.empty.eq(fifo.empty)
     ]
     # Parser
     mtrcntr = Signal(range(platform.motors))
     wordsreceived = Signal(range(wordsinmove(platform) + 1))
     error = Signal()
     # Peripheral state
     state = Signal(8)
     m.d.sync += [
         state[STATE.PARSING].eq(self.parse),
         state[STATE.FULL].eq(fifo.space_available <= 1),
         state[STATE.ERROR].eq(self.dispatcherror | error)
     ]
     # remember which word we are processing
     instruction = Signal(8)
     with m.FSM(reset='RESET', name='parser'):
         with m.State('RESET'):
             m.d.sync += [
                 self.parse.eq(1),
                 wordsreceived.eq(0),
                 error.eq(0)
             ]
             m.next = 'WAIT_COMMAND'
         with m.State('WAIT_COMMAND'):
             with m.If(interf.command_ready):
                 word = Cat(state[::-1], self.pinstate[::-1])
                 with m.If(interf.command == COMMANDS.EMPTY):
                     m.next = 'WAIT_COMMAND'
                 with m.Elif(interf.command == COMMANDS.START):
                     m.next = 'WAIT_COMMAND'
                     m.d.sync += self.parse.eq(1)
                 with m.Elif(interf.command == COMMANDS.STOP):
                     m.next = 'WAIT_COMMAND'
                     m.d.sync += self.parse.eq(0)
                 with m.Elif(interf.command == COMMANDS.WRITE):
                     m.d.sync += interf.word_to_send.eq(word)
                     with m.If(state[STATE.FULL] == 0):
                         m.next = 'WAIT_WORD'
                     with m.Else():
                         m.next = 'WAIT_COMMAND'
                 with m.Elif(interf.command == COMMANDS.READ):
                     m.d.sync += interf.word_to_send.eq(word)
                     m.next = 'WAIT_COMMAND'
                 with m.Elif(interf.command == COMMANDS.POSITION):
                     # position is requested multiple times for multiple
                     # motors
                     with m.If(mtrcntr < platform.motors - 1):
                         m.d.sync += mtrcntr.eq(mtrcntr + 1)
                     with m.Else():
                         m.d.sync += mtrcntr.eq(0)
                     m.d.sync += interf.word_to_send.eq(
                         self.position[mtrcntr])
                     m.next = 'WAIT_COMMAND'
         with m.State('WAIT_WORD'):
             with m.If(interf.word_complete):
                 byte0 = interf.word_received[:8]
                 with m.If(wordsreceived == 0):
                     with m.If((byte0 > 0) & (byte0 < 6)):
                         m.d.sync += [
                             instruction.eq(byte0),
                             fifo.write_en.eq(1),
                             wordsreceived.eq(wordsreceived + 1),
                             fifo.write_data.eq(interf.word_received)
                         ]
                         m.next = 'WRITE'
                     with m.Else():
                         m.d.sync += error.eq(1)
                         m.next = 'WAIT_COMMAND'
                 with m.Else():
                     m.d.sync += [
                         fifo.write_en.eq(1),
                         wordsreceived.eq(wordsreceived + 1),
                         fifo.write_data.eq(interf.word_received)
                     ]
                     m.next = 'WRITE'
         with m.State('WRITE'):
             m.d.sync += fifo.write_en.eq(0)
             wordslaser = wordsinscanline(
                 params(platform)['BITSINSCANLINE'])
             wordsmotor = wordsinmove(platform)
             with m.If(((instruction == INSTRUCTIONS.MOVE)
                        & (wordsreceived >= wordsmotor))
                       | (instruction == INSTRUCTIONS.WRITEPIN)
                       | (instruction == INSTRUCTIONS.LASTSCANLINE)
                       | ((instruction == INSTRUCTIONS.SCANLINE)
                          & (wordsreceived >= wordslaser))):
                 m.d.sync += [wordsreceived.eq(0), fifo.write_commit.eq(1)]
                 m.next = 'COMMIT'
             with m.Else():
                 m.next = 'WAIT_COMMAND'
         with m.State('COMMIT'):
             m.d.sync += fifo.write_commit.eq(0)
             m.next = 'WAIT_COMMAND'
     return m
예제 #21
0
    def elaborate(self, platform):
        m = Module()
        # add 1 MHz clock domain
        cntr = Signal(range(self.divider))
        # pos
        max_bits = (self.max_steps << self.bit_shift).bit_length()
        cntrs = Array(
            Signal(signed(max_bits + 1)) for _ in range(len(self.coeff)))
        assert max_bits <= 64
        ticks = Signal(MOVE_TICKS.bit_length())
        if self.top:
            steppers = [res for res in get_all_resources(platform, "stepper")]
            assert len(steppers) != 0
            for idx, stepper in enumerate(steppers):
                m.d.comb += [
                    stepper.step.eq(self.step[idx]),
                    stepper.dir.eq(self.dir[idx])
                ]
        else:
            self.ticks = ticks
            self.cntrs = cntrs

        # steps
        for motor in range(self.motors):
            m.d.comb += self.step[motor].eq(cntrs[motor *
                                                  self.order][self.bit_shift])

        # directions
        counter_d = Array(
            Signal(signed(max_bits + 1)) for _ in range(self.motors))
        for motor in range(self.motors):
            m.d.sync += counter_d[motor].eq(cntrs[motor * self.order])
            # negative case --> decreasing
            with m.If(counter_d[motor] > cntrs[motor * self.order]):
                m.d.sync += self.dir[motor].eq(0)
            # positive case --> increasing
            with m.Elif(counter_d[motor] < cntrs[motor * self.order]):
                m.d.sync += self.dir[motor].eq(1)
        with m.FSM(reset='RESET', name='polynomen'):
            with m.State('RESET'):
                m.next = 'WAIT_START'

                m.d.sync += self.busy.eq(0)
            with m.State('WAIT_START'):
                with m.If(self.start):
                    for motor in range(self.motors):
                        coef0 = motor * self.order
                        step_bit = self.bit_shift + 1
                        m.d.sync += [
                            cntrs[coef0].eq(cntrs[coef0][:step_bit]),
                            counter_d[motor].eq(counter_d[motor][:step_bit])
                        ]
                        for degree in range(1, self.order):
                            m.d.sync += cntrs[coef0 + degree].eq(0)
                    m.d.sync += self.busy.eq(1)
                    m.next = 'RUNNING'
                with m.Else():
                    m.d.sync += self.busy.eq(0)
            with m.State('RUNNING'):
                with m.If((ticks < self.ticklimit)
                          & (cntr >= self.divider - 1)):
                    m.d.sync += [ticks.eq(ticks + 1), cntr.eq(0)]
                    for motor in range(self.motors):
                        order = self.order
                        idx = motor * order
                        op3, op2, op1 = 0, 0, 0
                        if order > 2:
                            op3 += 3 * 2 * self.coeff[idx + 2] + cntrs[idx + 2]
                            op2 += cntrs[idx + 2]
                            op1 += self.coeff[idx + 2] + cntrs[idx + 2]
                            m.d.sync += cntrs[idx + 2].eq(op3)
                        if order > 1:
                            op2 += (2 * self.coeff[idx + 1] + cntrs[idx + 1])
                            m.d.sync += cntrs[idx + 1].eq(op2)
                        op1 += (self.coeff[idx + 1] + self.coeff[idx] +
                                cntrs[idx + 1] + cntrs[idx])
                        m.d.sync += cntrs[idx].eq(op1)
                with m.Elif(ticks < self.ticklimit):
                    m.d.sync += cntr.eq(cntr + 1)
                with m.Else():
                    m.d.sync += ticks.eq(0)
                    m.next = 'WAIT_START'
        return m
예제 #22
0
class TxNRZIEncoder(Elaboratable):
    """
    NRZI Encode

    In order to ensure there are enough bit transitions for a receiver to recover
    the clock usb uses NRZI encoding.  This module processes the incoming
    dj, dk, se0, and valid signals and decodes them to data values.  It
    also pipelines the se0 signal and passes it through unmodified.

    https://www.pjrc.com/teensy/beta/usb20.pdf, USB2 Spec, 7.1.8
    https://en.wikipedia.org/wiki/Non-return-to-zero

    Clock Domain
    ------------
    usb_48 : 48MHz

    Input Ports
    -----------
    i_valid : Signal()
        Qualifies oe, data, and se0.

    i_oe : Signal()
        Indicates that the transmit pipeline should be driving USB.

    i_data : Signal()
        Data bit to be transmitted on USB. Qualified by o_valid.

    i_se0 : Signal()
        Overrides value of o_data when asserted and indicates that SE0 state
        should be asserted on USB. Qualified by o_valid.

    Output Ports
    ------------
    o_usbp : Signal()
        Raw value of USB+ line.

    o_usbn : Signal()
        Raw value of USB- line.

    o_oe : Signal()
        When asserted it indicates that the tx pipeline should be driving USB.
    """
    def __init__(self):
        self.i_valid = Signal()
        self.i_oe = Signal()
        self.i_data = Signal()

        # flop all outputs
        self.o_usbp = Signal()
        self.o_usbn = Signal()
        self.o_oe = Signal()

    def elaborate(self, platform):
        m = Module()

        usbp = Signal()
        usbn = Signal()
        oe = Signal()

        # wait for new packet to start
        with m.FSM(domain="usb_io"):
            with m.State("IDLE"):
                m.d.comb += [
                    usbp.eq(1),
                    usbn.eq(0),
                    oe.eq(0),
                ]

                with m.If(self.i_valid & self.i_oe):
                    # first bit of sync always forces a transition, we idle
                    # in J so the first output bit is K.
                    m.next = "DK"

            # the output line is in state J
            with m.State("DJ"):
                m.d.comb += [
                    usbp.eq(1),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    with m.If(~self.i_oe):
                        m.next = "SE0A"
                    with m.Elif(self.i_data):
                        m.next = "DJ"
                    with m.Else():
                        m.next = "DK"

            # the output line is in state K
            with m.State("DK"):
                m.d.comb += [
                    usbp.eq(0),
                    usbn.eq(1),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    with m.If(~self.i_oe):
                        m.next = "SE0A"
                    with m.Elif(self.i_data):
                        m.next = "DK"
                    with m.Else():
                        m.next = "DJ"

            # first bit of the SE0 state
            with m.State("SE0A"):
                m.d.comb += [
                    usbp.eq(0),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    m.next = "SE0B"

            # second bit of the SE0 state
            with m.State("SE0B"):
                m.d.comb += [
                    usbp.eq(0),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    m.next = "EOPJ"

            # drive the bus back to J before relinquishing control
            with m.State("EOPJ"):
                m.d.comb += [
                    usbp.eq(1),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    m.next = "IDLE"

        m.d.usb_io += [
            self.o_oe.eq(oe),
            self.o_usbp.eq(usbp),
            self.o_usbn.eq(usbn),
        ]

        return m
예제 #23
0
    def elaborate(self, platform):
        m = Module()

        # If we have a bus translator, include it in our submodules.
        if self.translator:
            m.submodules.translator = self.translator

        #
        # Internal device state.
        #

        # Stores the device's current address. Used to identify which packets are for us.
        address = Signal(7, reset=0)

        # Stores the device's current configuration. Defaults to unconfigured.
        configuration = Signal(8, reset=0)

        #
        # Internal interconnections.
        #

        # Create our reset sequencer, which will be in charge of detecting USB port resets,
        # detecting high-speed hosts, and communicating that we are a high speed device.
        m.submodules.reset_sequencer = reset_sequencer = USBResetSequencer()

        m.d.comb += [
            reset_sequencer.bus_busy.eq(self.bus_busy),
            reset_sequencer.vbus_connected.eq(~self.utmi.session_end),
            reset_sequencer.line_state.eq(self.utmi.line_state),
        ]

        # Create our internal packet components:
        # - A token detector, which will identify and parse the tokens that start transactions.
        # - A data transmitter, which will transmit provided data streams.
        # - A data receiver, which will receive data from UTMI and convert it into streams.
        # - A handshake generator, which will assist in generating response packets.
        # - A handshake detector, which detects handshakes generated by the host.
        # - A data CRC16 handler, which will compute data packet CRCs.
        # - An interpacket delay timer, which will enforce interpacket delays.
        m.submodules.token_detector      = token_detector      = \
            USBTokenDetector(utmi=self.utmi, domain_clock=self.data_clock, fs_only=self.always_fs)
        m.submodules.transmitter = transmitter = USBDataPacketGenerator()
        m.submodules.receiver = receiver = USBDataPacketReceiver(
            utmi=self.utmi)
        m.submodules.handshake_generator = handshake_generator = USBHandshakeGenerator(
        )
        m.submodules.handshake_detector = handshake_detector = USBHandshakeDetector(
            utmi=self.utmi)
        m.submodules.data_crc = data_crc = USBDataPacketCRC()
        m.submodules.timer               = timer               = \
            USBInterpacketTimer(domain_clock=self.data_clock, fs_only=self.always_fs)

        # Connect our transmitter/receiver to our CRC generator.
        data_crc.add_interface(transmitter.crc)
        data_crc.add_interface(receiver.data_crc)

        # Connect our receiver to our timer.
        timer.add_interface(receiver.timer)

        m.d.comb += [
            # Ensure our token detector only responds to tokens addressed to us.
            token_detector.address.eq(address),

            # Hook up our data_crc to our receive inputs.
            data_crc.rx_data.eq(self.utmi.rx_data),
            data_crc.rx_valid.eq(self.utmi.rx_valid),

            # Connect our state signals to our subordinate components.
            token_detector.speed.eq(self.speed),
            timer.speed.eq(self.speed)
        ]

        #
        # Endpoint connections.
        #

        # Create our endpoint multiplexer...
        m.submodules.endpoint_mux = endpoint_mux = USBEndpointMultiplexer()
        endpoint_collection = endpoint_mux.shared

        # Connect our timer and CRC interfaces.
        timer.add_interface(endpoint_collection.timer)
        data_crc.add_interface(endpoint_collection.data_crc)

        m.d.comb += [
            # Low-level hardware interface.
            token_detector.interface.connect(endpoint_collection.tokenizer),
            handshake_detector.detected.connect(
                endpoint_collection.handshakes_in),

            # Device state.
            endpoint_collection.speed.eq(self.speed),
            endpoint_collection.active_config.eq(configuration),
            endpoint_collection.active_address.eq(address),

            # Receive interface.
            receiver.stream.connect(endpoint_collection.rx),
            endpoint_collection.rx_complete.eq(receiver.packet_complete),
            endpoint_collection.rx_invalid.eq(receiver.crc_mismatch),
            endpoint_collection.rx_ready_for_response.eq(
                receiver.ready_for_response),
            endpoint_collection.rx_pid_toggle.eq(receiver.active_pid[3]),

            # Transmit interface.
            endpoint_collection.tx.attach(transmitter.stream),
            handshake_generator.issue_ack.eq(
                endpoint_collection.handshakes_out.ack),
            handshake_generator.issue_nak.eq(
                endpoint_collection.handshakes_out.nak),
            handshake_generator.issue_stall.eq(
                endpoint_collection.handshakes_out.stall),
            transmitter.data_pid.eq(endpoint_collection.tx_pid_toggle),
        ]

        # If an endpoint wants to update our address or configuration, accept the update.
        with m.If(endpoint_collection.address_changed):
            m.d.usb += address.eq(endpoint_collection.new_address)
        with m.If(endpoint_collection.config_changed):
            m.d.usb += configuration.eq(endpoint_collection.new_config)

        # Finally, add each of our endpoints to this module and our multiplexer.
        for endpoint in self._endpoints:

            # Create a display name for the endpoint...
            name = endpoint.__class__.__name__
            if hasattr(m.submodules, name):
                name = f"{name}_{id(endpoint)}"

            # ... and add it, both as a submodule and to our multiplexer.
            endpoint_mux.add_interface(endpoint.interface)
            m.submodules[name] = endpoint

        #
        # Transmitter multiplexing.
        #

        # Create a multiplexer that will arbitrate access to the transmit lines.
        m.submodules.tx_multiplexer = tx_multiplexer = UTMIInterfaceMultiplexer(
        )

        # Connect each of our transmitters.
        tx_multiplexer.add_input(reset_sequencer.tx)
        tx_multiplexer.add_input(transmitter.tx)
        tx_multiplexer.add_input(handshake_generator.tx)

        m.d.comb += [
            # Connect our transmit multiplexer to the actual UTMI bus.
            tx_multiplexer.output.attach(self.utmi),

            # Connect up the transmit CRC interface to our UTMI bus.
            data_crc.tx_valid.eq(tx_multiplexer.output.valid
                                 & self.utmi.tx_ready),
            data_crc.tx_data.eq(tx_multiplexer.output.data),
        ]

        #
        # Device-state management.
        #

        # On a bus reset, clear our address and configuration.
        with m.If(reset_sequencer.bus_reset):
            m.d.usb += [
                address.eq(0),
                configuration.eq(0),
            ]

        # Device operating state controls.
        m.d.comb += [
            # Disable our host-mode pulldowns; as we're a device.
            self.utmi.dm_pulldown.eq(0),
            self.utmi.dp_pulldown.eq(0),

            # Let our reset sequencer set our USB mode and speed.
            reset_sequencer.low_speed_only.eq(self.low_speed_only
                                              & ~self.always_fs),
            reset_sequencer.full_speed_only.eq(self.full_speed_only
                                               | self.always_fs),
            self.utmi.op_mode.eq(reset_sequencer.operating_mode),
            self.utmi.xcvr_select.eq(reset_sequencer.current_speed),
            self.utmi.term_select.eq(reset_sequencer.termination_select
                                     & self.connect),
        ]

        #
        # Frame/microframe state.
        #

        # Handle each new SOF token as we receive them.
        with m.If(token_detector.interface.new_frame):

            # Update our knowledge of the current frame number.
            m.d.usb += self.frame_number.eq(token_detector.interface.frame)

            # Check if we're receiving a new 1ms frame -- which occurs when the new SOF's
            # frame number is different from the previous one's. This will always be the case
            # on full speed links; and will be the case 1/8th of the time on High Speed links.
            m.d.comb += self.new_frame.eq(
                token_detector.interface.frame != self.frame_number)

            # If this is a new frame, our microframe count should be zero.
            with m.If(self.new_frame):
                m.d.usb += self.microframe_number.eq(0)

            # Otherwise, this SOF indicates a new _microframe_ [USB 2.0: 8.4.3.1].
            with m.Else():
                m.d.usb += self.microframe_number.eq(self.microframe_number +
                                                     1)

        #
        # Device-state outputs.
        #
        m.d.comb += [
            self.speed.eq(reset_sequencer.current_speed),
            self.suspended.eq(reset_sequencer.suspended),
            self.sof_detected.eq(token_detector.interface.new_frame),
            self.reset_detected.eq(reset_sequencer.bus_reset),
            self.tx_activity_led.eq(tx_multiplexer.output.valid),
            self.rx_activity_led.eq(self.utmi.rx_valid)
        ]

        return m
예제 #24
0
    def elaborate(self, platform):
        m = Module()

        usbp = Signal()
        usbn = Signal()
        oe = Signal()

        # wait for new packet to start
        with m.FSM(domain="usb_io"):
            with m.State("IDLE"):
                m.d.comb += [
                    usbp.eq(1),
                    usbn.eq(0),
                    oe.eq(0),
                ]

                with m.If(self.i_valid & self.i_oe):
                    # first bit of sync always forces a transition, we idle
                    # in J so the first output bit is K.
                    m.next = "DK"

            # the output line is in state J
            with m.State("DJ"):
                m.d.comb += [
                    usbp.eq(1),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    with m.If(~self.i_oe):
                        m.next = "SE0A"
                    with m.Elif(self.i_data):
                        m.next = "DJ"
                    with m.Else():
                        m.next = "DK"

            # the output line is in state K
            with m.State("DK"):
                m.d.comb += [
                    usbp.eq(0),
                    usbn.eq(1),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    with m.If(~self.i_oe):
                        m.next = "SE0A"
                    with m.Elif(self.i_data):
                        m.next = "DK"
                    with m.Else():
                        m.next = "DJ"

            # first bit of the SE0 state
            with m.State("SE0A"):
                m.d.comb += [
                    usbp.eq(0),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    m.next = "SE0B"

            # second bit of the SE0 state
            with m.State("SE0B"):
                m.d.comb += [
                    usbp.eq(0),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    m.next = "EOPJ"

            # drive the bus back to J before relinquishing control
            with m.State("EOPJ"):
                m.d.comb += [
                    usbp.eq(1),
                    usbn.eq(0),
                    oe.eq(1),
                ]

                with m.If(self.i_valid):
                    m.next = "IDLE"

        m.d.usb_io += [
            self.o_oe.eq(oe),
            self.o_usbp.eq(usbp),
            self.o_usbn.eq(usbn),
        ]

        return m
예제 #25
0
    class USBDeviceController(Peripheral, Elaboratable):
        """ SoC controller for a USBDevice.

        Breaks our USBDevice control and status signals out into registers so a CPU / Wishbone master
        can control our USB device.

        The attributes below are intended to connect to a USBDevice. Typically, they'd be created by
        using the .controller() method on a USBDevice object, which will automatically connect all
        relevant signals.

        Attributes
        ----------

        connect: Signal(), output
            High when the USBDevice should be allowed to connect to a host.

        """
        def __init__(self):
            super().__init__()

            #
            # I/O port
            #
            self.connect = Signal(reset=1)
            self.bus_reset = Signal()

            #
            # Registers.
            #

            regs = self.csr_bank()
            self._connect = regs.csr(1,
                                     "rw",
                                     desc="""
                Set this bit to '1' to allow the associated USB device to connect to a host.
            """)

            self._speed = regs.csr(2,
                                   "r",
                                   desc="""
                Indicates the current speed of the USB device. 0 indicates High; 1 => Full,
                2 => Low, and 3 => SuperSpeed (incl SuperSpeed+).
            """)

            self._reset_irq = self.event(name="reset",
                                         desc="""
                Interrupt that occurs when a USB bus reset is received.
            """)

            # Wishbone connection.
            self._bridge = self.bridge(data_width=32,
                                       granularity=8,
                                       alignment=2)
            self.bus = self._bridge.bus
            self.irq = self._bridge.irq

        def attach(self, device: USBDevice):
            """ Returns a list of statements necessary to connect this to a USB controller.

            The returned values makes all of the connections necessary to provide control and fetch status
            from the relevant USB device. These can be made either combinationally or synchronously, but
            combinational is recommended; as these signals are typically fed from a register anyway.

            Parameters
            ----------
            device: USBDevice
                The :class:`USBDevice` object to be controlled.
            """
            return [
                device.connect.eq(self.connect),
                self.bus_reset.eq(device.reset_detected),
                self._speed.r_data.eq(device.speed)
            ]

        def elaborate(self, platform):
            m = Module()
            m.submodules.bridge = self._bridge

            # Core connection register.
            m.d.comb += self.connect.eq(self._connect.r_data)
            with m.If(self._connect.w_stb):
                m.d.usb += self._connect.r_data.eq(self._connect.w_data)

            # Reset-detection event.
            m.d.comb += self._reset_irq.stb.eq(self.bus_reset)

            return m
예제 #26
0
class TxBitstuffer(Elaboratable):
    """
    Bitstuff Insertion

    Long sequences of 1's would cause the receiver to lose it's lock on the
    transmitter's clock.  USB solves this with bitstuffing.  A '0' is stuffed
    after every 6 consecutive 1's.

    The TxBitstuffer is the only component in the transmit pipeline that can
    delay transmission of serial data.  It is therefore responsible for
    generating the bit_strobe signal that keeps the pipe moving forward.

    https://www.pjrc.com/teensy/beta/usb20.pdf, USB2 Spec, 7.1.9
    https://en.wikipedia.org/wiki/Bit_stuffing

    Clock Domain
    ------------
    usb_12 : 48MHz

    Input Ports
    ------------
    i_data : Signal()
        Data bit to be transmitted on USB.

    Output Ports
    ------------
    o_data : Signal()
        Data bit to be transmitted on USB.

    o_stall : Signal()
        Used to apply backpressure on the tx pipeline.
    """
    def __init__(self):
        self.i_data = Signal()

        self.o_stall = Signal()
        self.o_will_stall = Signal()
        self.o_data = Signal()

    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
예제 #27
0
    def elaborate(self, platform):
        self.m = m = Module()

        comb = m.d.comb
        sync = m.d.sync

        # CPU units used.
        logic = m.submodules.logic = LogicUnit()
        adder = m.submodules.adder = AdderUnit()
        shifter = m.submodules.shifter = ShifterUnit()
        compare = m.submodules.compare = CompareUnit()

        self.current_priv_mode = Signal(PrivModeBits,
                                        reset=PrivModeBits.MACHINE)

        csr_unit = self.csr_unit = m.submodules.csr_unit = CsrUnit(
            # TODO does '==' below produces the same synth result as .all()?
            in_machine_mode=self.current_priv_mode == PrivModeBits.MACHINE)
        exception_unit = self.exception_unit = m.submodules.exception_unit = ExceptionUnit(
            csr_unit=csr_unit, current_priv_mode=self.current_priv_mode)
        arbiter = self.arbiter = m.submodules.arbiter = MemoryArbiter(
            mem_config=self.mem_config,
            with_addr_translation=True,
            csr_unit=csr_unit,  # SATP register
            exception_unit=exception_unit,  # current privilege mode
        )
        mem_unit = m.submodules.mem_unit = MemoryUnit(mem_port=arbiter.port(
            priority=0))

        ibus = arbiter.port(priority=2)

        if self.with_debug:
            m.submodules.debug = self.debug = DebugUnit(self)
            self.debug_bus = arbiter.port(priority=1)

        # Current decoding state signals.
        instr = self.instr = Signal(32)
        funct3 = self.funct3 = Signal(3)
        funct7 = self.funct7 = Signal(7)
        rd = self.rd = Signal(5)
        rs1 = Signal(5)
        rs2 = Signal(5)
        rs1val = Signal(32)
        rs2val = Signal(32)
        rdval = Signal(32)  # calculated by unit, stored to register file
        imm = Signal(signed(12))
        csr_idx = Signal(12)
        uimm = Signal(20)
        opcode = self.opcode = Signal(InstrType)
        pc = self.pc = Signal(32, reset=CODE_START_ADDR)

        # at most one active_unit at any time
        active_unit = ActiveUnit()

        # Register file. Contains two read ports (for rs1, rs2) and one write port.
        regs = Memory(width=32, depth=32, init=self.reg_init)
        reg_read_port1 = m.submodules.reg_read_port1 = regs.read_port()
        reg_read_port2 = m.submodules.reg_read_port2 = regs.read_port()
        reg_write_port = (self.reg_write_port
                          ) = m.submodules.reg_write_port = regs.write_port()

        # Timer management.
        mtime = self.mtime = Signal(32)
        sync += mtime.eq(mtime + 1)
        comb += csr_unit.mtime.eq(mtime)

        self.halt = Signal()
        with m.If(csr_unit.mstatus.mie & csr_unit.mie.mtie):
            with m.If(mtime == csr_unit.mtimecmp):
                # 'halt' signal needs to be cleared when CPU jumps to trap handler.
                sync += [
                    self.halt.eq(1),
                ]

        comb += [
            exception_unit.m_instruction.eq(instr),
            exception_unit.m_pc.eq(pc),
            # TODO more
        ]

        # TODO
        # DebugModule is able to read and write GPR values.
        # if self.with_debug:
        #     comb += self.halt.eq(self.debug.HALT)
        # else:
        #     comb += self.halt.eq(0)

        # with m.If(self.halt):
        #     comb += [
        #         reg_read_port1.addr.eq(self.gprf_debug_addr),
        #         reg_write_port.addr.eq(self.gprf_debug_addr),
        #         reg_write_port.en.eq(self.gprf_debug_write_en)
        #     ]

        #     with m.If(self.gprf_debug_write_en):
        #         comb += reg_write_port.data.eq(self.gprf_debug_data)
        #     with m.Else():
        #         comb += self.gprf_debug_data.eq(reg_read_port1.data)
        with m.If(0):
            pass
        with m.Else():
            comb += [
                reg_read_port1.addr.eq(rs1),
                reg_read_port2.addr.eq(rs2),
                reg_write_port.addr.eq(rd),
                reg_write_port.data.eq(rdval),
                # reg_write_port.en set later
                rs1val.eq(reg_read_port1.data),
                rs2val.eq(reg_read_port2.data),
            ]

        comb += [
            # following is not true for all instrutions, but in specific cases will be overwritten later
            imm.eq(instr[20:32]),
            csr_idx.eq(instr[20:32]),
            uimm.eq(instr[12:]),
        ]

        # drive input signals of actually used unit.
        with m.If(active_unit.logic):
            comb += [
                logic.funct3.eq(funct3),
                logic.src1.eq(rs1val),
                logic.src2.eq(Mux(opcode == InstrType.OP_IMM, imm, rs2val)),
            ]
        with m.Elif(active_unit.adder):
            comb += [
                adder.src1.eq(rs1val),
                adder.src2.eq(Mux(opcode == InstrType.OP_IMM, imm, rs2val)),
            ]
        with m.Elif(active_unit.shifter):
            comb += [
                shifter.funct3.eq(funct3),
                shifter.funct7.eq(funct7),
                shifter.src1.eq(rs1val),
                shifter.shift.eq(
                    Mux(opcode == InstrType.OP_IMM, imm[0:5].as_unsigned(),
                        rs2val[0:5])),
            ]
        with m.Elif(active_unit.mem_unit):
            comb += [
                mem_unit.en.eq(1),
                mem_unit.funct3.eq(funct3),
                mem_unit.src1.eq(rs1val),
                mem_unit.src2.eq(rs2val),
                mem_unit.store.eq(opcode == InstrType.STORE),
                mem_unit.offset.eq(
                    Mux(opcode == InstrType.LOAD, imm, Cat(rd, imm[5:12]))),
            ]
        with m.Elif(active_unit.compare):
            comb += [
                compare.funct3.eq(funct3),
                # Compare Unit uses Adder for carry and overflow flags.
                adder.src1.eq(rs1val),
                adder.src2.eq(Mux(opcode == InstrType.OP_IMM, imm, rs2val)),
                # adder.sub set somewhere below
            ]
        with m.Elif(active_unit.branch):
            comb += [
                compare.funct3.eq(funct3),
                # Compare Unit uses Adder for carry and overflow flags.
                adder.src1.eq(rs1val),
                adder.src2.eq(rs2val),
                # adder.sub set somewhere below
            ]
        with m.Elif(active_unit.csr):
            comb += [
                csr_unit.func3.eq(funct3),
                csr_unit.csr_idx.eq(csr_idx),
                csr_unit.rs1.eq(rs1),
                csr_unit.rs1val.eq(rs1val),
                csr_unit.rd.eq(rd),
                csr_unit.en.eq(1),
            ]

        comb += [
            compare.negative.eq(adder.res[-1]),
            compare.overflow.eq(adder.overflow),
            compare.carry.eq(adder.carry),
            compare.zero.eq(adder.res == 0),
        ]

        # Decoding state (with redundancy - instr. type not known yet).
        # We use 'ibus.read_data' instead of 'instr' (that is driven by sync domain)
        # for getting registers to save 1 cycle.
        comb += [
            opcode.eq(instr[0:7]),
            rd.eq(instr[7:12]),
            funct3.eq(instr[12:15]),
            rs1.eq(instr[15:20]),
            rs2.eq(instr[20:25]),
            funct7.eq(instr[25:32]),
        ]

        def fetch_with_new_pc(pc: Signal):
            m.next = "FETCH"
            m.d.sync += active_unit.eq(0)
            m.d.sync += self.pc.eq(pc)

        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)

        self.fetch = Signal()
        interconnect_error = Signal()
        comb += interconnect_error.eq(exception_unit.m_store_error
                                      | exception_unit.m_fetch_error
                                      | exception_unit.m_load_error)
        with m.FSM():
            with m.State("FETCH"):
                with m.If(self.halt):
                    sync += self.halt.eq(0)
                    trap(IrqCause.M_TIMER_INTERRUPT, interrupt=True)
                with m.Else():
                    with m.If(pc & 0b11):
                        trap(TrapCause.FETCH_MISALIGNED)
                    with m.Else():
                        comb += [
                            ibus.en.eq(1),
                            ibus.store.eq(0),
                            ibus.addr.eq(pc),
                            ibus.mask.eq(0b1111),
                            ibus.is_fetch.eq(1),
                        ]
                    with m.If(interconnect_error):
                        trap(cause=None)
                    with m.If(ibus.ack):
                        sync += [
                            instr.eq(ibus.read_data),
                        ]
                        m.next = "DECODE"
            with m.State("DECODE"):
                comb += self.fetch.eq(
                    1
                )  # only for simulation, notify that 'instr' ready to use.
                m.next = "EXECUTE"
                # here, we have registers already fetched into rs1val, rs2val.
                with m.If(instr & 0b11 != 0b11):
                    trap(TrapCause.ILLEGAL_INSTRUCTION)
                with m.If(match_logic_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.logic.eq(1),
                    ]
                with m.Elif(match_adder_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.adder.eq(1),
                        adder.sub.eq((opcode == InstrType.ALU)
                                     & (funct7 == Funct7.SUB)),
                    ]
                with m.Elif(match_shifter_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.shifter.eq(1),
                    ]
                with m.Elif(match_loadstore_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.mem_unit.eq(1),
                    ]
                with m.Elif(match_compare_unit(opcode, funct3, funct7)):
                    sync += [
                        active_unit.compare.eq(1),
                        adder.sub.eq(1),
                    ]
                with m.Elif(match_lui(opcode, funct3, funct7)):
                    sync += [
                        active_unit.lui.eq(1),
                    ]
                    comb += [
                        reg_read_port1.addr.eq(rd),
                        # rd will be available in next cycle in rs1val
                    ]
                with m.Elif(match_auipc(opcode, funct3, funct7)):
                    sync += [
                        active_unit.auipc.eq(1),
                    ]
                with m.Elif(match_jal(opcode, funct3, funct7)):
                    sync += [
                        active_unit.jal.eq(1),
                    ]
                with m.Elif(match_jalr(opcode, funct3, funct7)):
                    sync += [
                        active_unit.jalr.eq(1),
                    ]
                with m.Elif(match_branch(opcode, funct3, funct7)):
                    sync += [
                        active_unit.branch.eq(1),
                        adder.sub.eq(1),
                    ]
                with m.Elif(match_csr(opcode, funct3, funct7)):
                    sync += [active_unit.csr.eq(1)]
                with m.Elif(match_mret(opcode, funct3, funct7)):
                    sync += [active_unit.mret.eq(1)]
                with m.Elif(match_sfence_vma(opcode, funct3, funct7)):
                    pass  # sfence.vma
                with m.Elif(opcode == 0b0001111):
                    pass  # fence
                with m.Else():
                    trap(TrapCause.ILLEGAL_INSTRUCTION)
            with m.State("EXECUTE"):
                with m.If(active_unit.logic):
                    sync += [
                        rdval.eq(logic.res),
                    ]
                with m.Elif(active_unit.adder):
                    sync += [
                        rdval.eq(adder.res),
                    ]
                with m.Elif(active_unit.shifter):
                    sync += [
                        rdval.eq(shifter.res),
                    ]
                with m.Elif(active_unit.mem_unit):
                    sync += [
                        rdval.eq(mem_unit.res),
                    ]
                with m.Elif(active_unit.compare):
                    sync += [
                        rdval.eq(compare.condition_met),
                    ]
                with m.Elif(active_unit.lui):
                    sync += [
                        rdval.eq(Cat(Const(0, 12), uimm)),
                    ]
                with m.Elif(active_unit.auipc):
                    sync += [
                        rdval.eq(pc + Cat(Const(0, 12), uimm)),
                    ]
                with m.Elif(active_unit.jal | active_unit.jalr):
                    sync += [
                        rdval.eq(pc + 4),
                    ]
                with m.Elif(active_unit.csr):
                    sync += [rdval.eq(csr_unit.rd_val)]

                # control flow mux - all traps need to be here, otherwise it will overwrite m.next statement.
                with m.If(active_unit.mem_unit):
                    with m.If(mem_unit.ack):
                        m.next = "WRITEBACK"
                        sync += active_unit.eq(0)
                    with m.Else():
                        m.next = "EXECUTE"
                    with m.If(interconnect_error):
                        # NOTE:
                        # the order of that 'If' is important.
                        # In case of error overwrite m.next above.
                        trap(cause=None)
                with m.Elif(active_unit.csr):
                    with m.If(csr_unit.illegal_insn):
                        trap(TrapCause.ILLEGAL_INSTRUCTION)
                    with m.Else():
                        with m.If(csr_unit.vld):
                            m.next = "WRITEBACK"
                            sync += active_unit.eq(0)
                        with m.Else():
                            m.next = "EXECUTE"
                with m.Elif(active_unit.mret):
                    comb += exception_unit.m_mret.eq(1)
                    fetch_with_new_pc(exception_unit.mepc)
                with m.Else():
                    # all units not specified by default take 1 cycle
                    m.next = "WRITEBACK"
                    sync += active_unit.eq(0)

                jal_offset = Signal(signed(21))
                comb += jal_offset.eq(
                    Cat(
                        Const(0, 1),
                        instr[21:31],
                        instr[20],
                        instr[12:20],
                        instr[31],
                    ).as_signed())

                pc_addend = Signal(signed(32))
                sync += pc_addend.eq(Mux(active_unit.jal, jal_offset, 4))

                branch_addend = Signal(signed(13))
                comb += branch_addend.eq(
                    Cat(
                        Const(0, 1),
                        instr[8:12],
                        instr[25:31],
                        instr[7],
                        instr[31],
                    ).as_signed()  # TODO is it ok that it's signed?
                )

                with m.If(active_unit.branch):
                    with m.If(compare.condition_met):
                        sync += pc_addend.eq(branch_addend)

                new_pc = Signal(32)
                is_jalr_latch = Signal()  # that's bad workaround
                with m.If(active_unit.jalr):
                    sync += is_jalr_latch.eq(1)
                    sync += new_pc.eq(rs1val.as_signed() + imm)

            with m.State("WRITEBACK"):
                with m.If(is_jalr_latch):
                    sync += pc.eq(new_pc)
                with m.Else():
                    sync += pc.eq(pc + pc_addend)
                sync += is_jalr_latch.eq(0)

                # Here, rdval is already calculated. If neccessary, put it into register file.
                should_write_rd = self.should_write_rd = Signal()
                writeback = self.writeback = Signal()
                # for riscv-dv simulation:
                # detect that instruction does not perform register write to avoid infinite loop
                # by checking writeback & should_write_rd
                # TODO it will break for trap-causing instructions.
                comb += writeback.eq(1)
                comb += should_write_rd.eq(
                    reduce(
                        or_,
                        [
                            match_shifter_unit(opcode, funct3, funct7),
                            match_adder_unit(opcode, funct3, funct7),
                            match_logic_unit(opcode, funct3, funct7),
                            match_load(opcode, funct3, funct7),
                            match_compare_unit(opcode, funct3, funct7),
                            match_lui(opcode, funct3, funct7),
                            match_auipc(opcode, funct3, funct7),
                            match_jal(opcode, funct3, funct7),
                            match_jalr(opcode, funct3, funct7),
                            match_csr(opcode, funct3, funct7),
                        ],
                    )
                    & (rd != 0))

                with m.If(should_write_rd):
                    comb += reg_write_port.en.eq(True)
                m.next = "FETCH"

        return m
예제 #28
0
    def __init__(self):
        self.i_data = Signal()

        self.o_stall = Signal()
        self.o_will_stall = Signal()
        self.o_data = Signal()
예제 #29
0
class ValueAddressGenerator(SimpleElaboratable):
    """Generates addresses within a single pixel.

    Specifically for a 4x4 2DConv, works with a PixelAddressGenerator to find
    addresses of individual values. It reads `depth` * 4 * 32bit words,
    then moves down and repeats this. An external counter re-starts the
    generator once it has read 4 complete rows of input.

    Attributes
    ----------

    start: Signal, in
        Begin generating addresses from the start_addr.

    start_addr: Signal(14), in
        Address of start of first pixel, from a PixelAddressGenerator.

    depth: Signal(3), in
        Number of 16-byte blocks to read per pixel. Max depth is 7 which is 112
        values/pixel).

    num_blocks_y: Signal(10), in
        Number of blocks per row.

    addr_out: Signal(14), out
        Current output address
    """

    def __init__(self):
        self.start = Signal()
        self.start_addr = Signal(14)
        self.depth = Signal(3)
        self.num_blocks_y = Signal(10)
        self.addr_out = Signal(14)

    def elab(self, m):
        x_count = Signal(7)
        next_row_addr = Signal(14)
        addr = Signal(14)

        with m.If(self.start):
            # Start overrides other behaviors
            m.d.comb += self.addr_out.eq(self.start_addr)
            m.d.sync += [
                addr.eq(self.start_addr),
                x_count.eq(1),
                next_row_addr.eq(self.start_addr + self.num_blocks_y),
            ]
        with m.Else():
            m.d.comb += self.addr_out.eq(addr)
            # x_size is the number of cycles to read 4 consecutive pixels
            x_size = Signal(7)
            m.d.comb += x_size.eq(self.depth << 4)
            with m.If(x_count != (x_size - 1)):
                m.d.sync += x_count.eq(x_count + 1)
                with m.If(x_count[:2] == 3):
                    m.d.sync += addr.eq(addr + 1)
            with m.Else():
                # x_count == x_size - 1 ==> End of row
                m.d.sync += [
                    addr.eq(next_row_addr),
                    next_row_addr.eq(next_row_addr + self.num_blocks_y),
                    x_count.eq(0),
                ]
예제 #30
0
class USBOutStreamBoundaryDetector(Elaboratable):
    """ Gateware that detects USBOutStream packet boundaries, and generates First and Last signals.

    As UTMI/ULPI do not denote the last byte of a packet; this module injects two bytes of delay in
    order to correctly identify the last bytes.

    Attributes
    ----------
    unprocessed_stream: USBOutStreamInterface, input stream
        The stream to work with; will be processed and then output on :attr:``processed_stream``.
    processed_stream: USBOutStreamInterface, output stream
        The stream produced by this module. This stream is two bytes delayed from :attr:``unprocessed_stream``;
        and in-phase with the :attr::``first`` and :attr::``last`` signals.

    complete_in: Signal(), input, optional
        Input that accepts an RxComplete signal. If provided; a delayed version will be produced on
        :attr:``complete_out`` after a :attr:``processed_stream`` packet terminates.
    invalid_in: Signal(), input, optional
        Input that accepts an RxInvalid signal. If provided; a delayed version will be produced on
        :attr:``complete_out`` after a :attr:``processed_stream`` packet terminates.


    complete_out: Signal(), output
        If :attr:``complete_in`` is provided; this signal provides a delayed version of that signal
        timed so it is strobed after :attr:``processed_stream`` packets complete.
    invalid_out: Signal(), output
        If :attr:``invalid_out`` is provided; this signal provides a delayed version of that signal
        timed so it is strobed after :attr:``processed_stream`` packets complete.

    first: Signal(), output
        Indicates that the byte present on :attr:``processed_stream`` is the first byte of a packet.
    last: Signal(), output
        Indicates that the byte present on :attr:``processed_stream`` is the last byte of a packet.

    Parameters
    ----------
    domain: str
        The name of the domain the stream belongs to; defaults to "usb".
    """
    def __init__(self, domain="usb"):

        self._domain = domain

        #
        # I/O port
        #
        self.unprocessed_stream = USBOutStreamInterface()
        self.processed_stream = USBOutStreamInterface()

        self.complete_in = Signal()
        self.invalid_in = Signal()

        self.complete_out = Signal()
        self.invalid_out = Signal()

        self.first = Signal()
        self.last = Signal()

    def elaborate(self, platform):
        m = Module()

        in_stream = self.unprocessed_stream
        out_stream = self.processed_stream

        # We'll buffer a single byte of the stream, so we can always be one byte ahead.
        buffered_byte = Signal(8)
        is_first_byte = Signal()

        buffered_complete = Signal()
        buffered_invalid = Signal()

        with m.FSM(domain='usb'):

            # WAIT_FOR_FIRST_BYTE -- we're not actively receiving data, yet. Wait for the
            # first byte of a new packet.
            with m.State('WAIT_FOR_FIRST_BYTE'):
                m.d.usb += out_stream.valid.eq(0)

                m.d.usb += [
                    # We have no data to output, so this can't be our first or last bytes...
                    self.first.eq(0),
                    self.last.eq(0),
                    out_stream.next.eq(0),

                    # ... and we can't have gotten a complete or invalid strobe that matters to us.
                    buffered_complete.eq(0),
                    buffered_invalid.eq(0),
                    self.complete_out.eq(0),
                    self.invalid_out.eq(0),
                ]

                # Once we've received our first byte, buffer it, and mark it as our first byte.
                with m.If(in_stream.valid & in_stream.next):
                    m.d.usb += [
                        buffered_byte.eq(in_stream.payload),
                        is_first_byte.eq(1)
                    ]
                    m.next = 'RECEIVE_AND_TRANSMIT'

            # RECEIVE_AND_TRANSMIT -- receive incoming bytes, and transmit our buffered bytes.
            # We'll transmit one byte per byte received; ensuring we always retain a single byte --
            # our last byte.
            with m.State('RECEIVE_AND_TRANSMIT'):
                m.d.usb += [out_stream.valid.eq(1), out_stream.next.eq(0)]

                # Buffer any complete/invalid signals we get while receiving, so we don't output
                # them before we finish outputting our processed stream.
                m.d.usb += [
                    buffered_complete.eq(buffered_complete | self.complete_in),
                    buffered_invalid.eq(buffered_invalid | self.invalid_in)
                ]

                # If we get a new byte, emit our buffered byte, and store the incoming byte.
                with m.If(in_stream.valid & in_stream.next):
                    m.d.usb += [
                        # Output our buffered byte...
                        out_stream.payload.eq(buffered_byte),
                        out_stream.next.eq(1),

                        # indicate whether our current byte was the first byte captured...
                        self.first.eq(is_first_byte),

                        # ... and store the new, incoming byte.
                        buffered_byte.eq(in_stream.payload),
                        is_first_byte.eq(0)
                    ]

                # Once we no longer have an active packet, transmit our _last_ byte,
                # and move back to waiting for an active packet.
                with m.If(~in_stream.valid):
                    m.d.usb += [

                        # Output our buffered byte...
                        out_stream.payload.eq(buffered_byte),
                        out_stream.next.eq(1),
                        self.first.eq(is_first_byte),

                        # ... and indicate that it's the last byte in our stream.
                        self.last.eq(1)
                    ]
                    m.next = 'OUTPUT_STROBES'

            with m.State('OUTPUT_STROBES'):
                m.d.usb += [
                    # We've just finished transmitting our processed stream; so clear our data strobes...
                    self.first.eq(0),
                    self.last.eq(0),
                    out_stream.next.eq(0),

                    # ... and output our buffered complete/invalid strobes.
                    self.complete_out.eq(buffered_complete),
                    self.invalid_out.eq(buffered_invalid)
                ]
                m.next = 'WAIT_FOR_FIRST_BYTE'

        if self._domain != "usb":
            m = DomainRenamer({"usb": self._domain})(m)

        return m