Beispiel #1
0
    def elaborate(self, platform):
        m = Module()

        # Event timer: keeps track of the timing of each of the individual event phases.
        timer = Signal(range(0, self._CYCLES_3_MILLISECONDS + 1))

        # Line state timer: keeps track of how long we've seen a line-state of interest;
        # other than a reset SE0. Used to track chirp and idle times.
        line_state_time = Signal(range(0, self._CYCLES_3_MILLISECONDS + 1))

        # Valid pairs: keeps track of how make Chirp K / Chirp J sequences we've
        # seen, thus far.
        valid_pairs = Signal(range(0, 4))

        # Tracks whether we were at high speed when we entered a suspend state.
        was_hs_pre_suspend = Signal()

        # By default, always count forward in time.
        # We'll reset the timer below when appropriate.
        m.d.usb += timer.eq(_generate_wide_incrementer(m, platform, timer))
        m.d.usb += line_state_time.eq(_generate_wide_incrementer(m, platform, line_state_time))

        # Signal that indicates when the bus is idle.
        # Our bus's IDLE condition depends on our active speed.
        bus_idle = Signal()

        # High speed busses present SE0 (which we see as SQUELCH'd) when idle [USB2.0: 7.1.1.3].
        with m.If(self.current_speed == USBSpeed.HIGH):
            m.d.comb += bus_idle.eq(self.line_state == self._LINE_STATE_SQUELCH)

        # Full and low-speed busses see a 'J' state when idle, due to the device pull-up restistors.
        # (The line_state values for these are flipped between speeds.) [USB2.0: 7.1.7.4.1; USB2.0: Table 7-2].
        with m.Elif(self.current_speed == USBSpeed.FULL):
            m.d.comb += bus_idle.eq(self.line_state == self._LINE_STATE_FS_HS_J)
        with m.Else():
            m.d.comb += bus_idle.eq(self.line_state == self._LINE_STATE_LS_J)


        #
        # Core reset sequences.
        #
        with m.FSM(domain='usb'):

            # INITIALIZE -- we're immediately post-reset; we'll perform some minor setup
            with m.State('INITIALIZE'):

                # If we're working in low-speed mode, configure the PHY accordingly.
                with m.If(self.low_speed_only):
                    m.d.usb += self.current_speed.eq(USBSpeed.LOW)

                m.next = 'LS_FS_NON_RESET'
                m.d.usb += [
                    timer.eq(0),
                    line_state_time.eq(0)
                ]

            # LS_FS_NON_RESET -- we're currently operating at LS/FS and waiting for a reset;
            # the device could be active or inactive, but we haven't yet seen a reset condition.
            with m.State('LS_FS_NON_RESET'):

                # If we're seeing a state other than SE0 (D+ / D- at zero), this isn't yet a
                # potential reset. Keep our timer at zero.
                with m.If(self.line_state != self._LINE_STATE_SE0):
                    m.d.usb += timer.eq(0)


                # If VBUS isn't connected, don't go through the whole reset process;
                # but also consider ourselves permanently in reset. This ensures we
                # don't progress through the reset FSM; but also ensures the device
                # state starts fresh with each plug.
                with m.If(~self.vbus_connected):
                    m.d.usb  += timer.eq(0)
                    m.d.comb += self.bus_reset.eq(1)

                # If we see an SE0 for >2.5uS; < 3ms, this a bus reset.
                # We'll trigger a reset after 5uS; providing a little bit of timing flexibility.
                # [USB2.0: 7.1.7.5; ULPI 3.8.5.1].
                with m.If(timer == self._CYCLES_5_MICROSECONDS):
                    m.d.comb += self.bus_reset.eq(1)

                    # If we're okay to run in high speed, we'll try to perform a high-speed detect.
                    with m.If(~self.low_speed_only & ~self.full_speed_only):
                        m.next = 'START_HS_DETECTION'


                # If we're seeing a state other than IDLE, clear our suspend timer.
                with m.If(~bus_idle):
                    m.d.usb += line_state_time.eq(0)

                # If we see 3ms of consecutive line idle, we're being put into USB suspend.
                # We'll enter our suspended state, directly. [USB2.0: 7.1.7.6]
                with m.If(line_state_time == self._CYCLES_3_MILLISECONDS):
                    m.d.usb += was_hs_pre_suspend.eq(0)
                    m.next = 'SUSPENDED'




            # HS_NON_RESET -- we're currently operating at high speed and waiting for a reset or
            # suspend; the device could be active or inactive.
            with m.State('HS_NON_RESET'):

                # If we're seeing a state other than SE0 (D+ / D- at zero), this isn't yet a
                # potential reset. Keep our timer at zero.
                with m.If(self.line_state != self._LINE_STATE_SE0):
                    m.d.usb += timer.eq(0)

                # If VBUS isn't connected, our device/host relationship is effectively
                # a blank state. We'll want to present our detection pull-up to the host,
                # so we'll drop out of high speed.
                with m.If(~self.vbus_connected):
                    m.d.comb += self.bus_reset.eq(1)
                    m.next = 'IS_LOW_OR_FULL_SPEED'


                # High speed signaling presents IDLE and RESET the same way: with the host
                # driving SE0; and us seeing SQUELCH. [USB2.0: 7.1.1.3; USB2.0: 7.1.7.6].
                # Either way, our next step is the same: we'll drop down to full-speed. [USB2.0: 7.1.7.6]
                # Afterwards, we'll take steps to differentiate a reset from a suspend.
                with m.If(timer == self._CYCLES_3_MILLISECONDS):
                    m.d.usb += [
                        timer                    .eq(0),

                        self.current_speed       .eq(USBSpeed.FULL),
                        self.operating_mode      .eq(UTMIOperatingMode.NORMAL),
                        self.termination_select  .eq(UTMITerminationSelect.LS_FS_NORMAL),
                    ]
                    m.next = 'DETECT_HS_SUSPEND'


                # If we see full-speed-only or low-speed-only being driven, switch
                # back to our LS/FS mode.
                with m.If(self.full_speed_only | self.low_speed_only):
                    m.next = 'IS_LOW_OR_FULL_SPEED'


            # START_HS_DETECTION -- entry state for high-speed detection
            with m.State('START_HS_DETECTION'):
                m.d.usb += [
                    timer                    .eq(0),

                    # Switch into High-speed chirp mode. Note that we'll need to leave our
                    # terminations set to '1' until we're sure this is a high-speed host;
                    # or the host will see our pull-up removal as a disconnect.
                    self.current_speed       .eq(USBSpeed.HIGH),
                    self.operating_mode      .eq(UTMIOperatingMode.CHIRP),
                    self.termination_select  .eq(UTMITerminationSelect.HS_CHIRP)
                ]
                m.next = 'PREPARE_FOR_CHIRP_0'


            # PREPARE_FOR_CHIRP_0 / PREPARE_FOR_CHIRP_1-- wait states; in which we give the PHY
            # time to the mode we'll need to drive our high-speed chirp.
            with m.State('PREPARE_FOR_CHIRP_0'):
                with m.If(~self.bus_busy):
                    m.next = 'PREPARE_FOR_CHIRP_1'

            with m.State('PREPARE_FOR_CHIRP_1'):
                with m.If(~self.bus_busy):
                    m.next = 'DEVICE_CHIRP'


            # DEVICE_CHIRP -- the device produces a 'chirp' K, which advertises to the host that
            # we're high speed capable. We'll provide that chirp K for around ~2ms. [USB2.0: 7.1.7.5]
            with m.State('DEVICE_CHIRP'):

                # Transmit a constant stream of 0's, which in this mode is a Chirp K.
                # Note that we don't need to check 'ready', as we care about the length
                # of time, rather than the number of bits.
                m.d.comb += [
                    self.tx.valid  .eq(1),
                    self.tx.data   .eq(0)
                ]

                # Once 2ms have passed, we can stop our chirp, and begin waiting for the
                # hosts's response. We'll wait for Ready to be asserted to do so, to ensure
                # we don't change our values in the middle of a bit.
                with m.If((timer == self._CYCLES_2_MILLISECONDS)):
                    m.d.usb += [
                        timer        .eq(0),
                        valid_pairs  .eq(0)
                    ]
                    m.next = 'AWAIT_HOST_K'


            # AWAIT_HOST_K -- we've now completed the device chirp; and are waiting to see if the host
            # will respond with an alternating sequence of K's and J's.
            with m.State('AWAIT_HOST_K'):

                # If we don't see our response within 2.5ms, this isn't a compliant HS host. [USB2.0: 7.1.7.5].
                # This is thus a full-speed host, and we'll act as a full-speed device.
                with m.If(timer == self._CYCLES_2P5_MILLISECONDS):
                    m.next = 'IS_LOW_OR_FULL_SPEED'

                # Once we've seen our K, we're good to start observing J/K toggles.
                with m.If(self.line_state == self._LINE_STATE_FS_HS_K):
                    m.next = 'IN_HOST_K'
                    m.d.usb += line_state_time.eq(0)


            # IN_HOST_K: we're seeing a host Chirp K as part of our handshake; we'll
            # time it and see how long it lasts
            with m.State('IN_HOST_K'):

                # If we've exceeded our minimum chirp time, consider this a valid pattern
                # bit, # and advance in the pattern.
                with m.If(line_state_time == self._CYCLES_2P5_MICROSECONDS):
                    m.next = 'AWAIT_HOST_J'

                # If our input has become something other than a K, then
                # we haven't finished our sequence. We'll go back to expecting a K.
                with m.If(self.line_state != self._LINE_STATE_FS_HS_K):
                    m.next = 'AWAIT_HOST_K'

                # Time out if we exceed our maximum allowed duration.
                with m.If(timer == self._CYCLES_2P5_MILLISECONDS):
                    m.next = 'IS_LOW_OR_FULL_SPEED'


            # AWAIT_HOST_J -- we're waiting for the next Chirp J in the host chirp sequence
            with m.State('AWAIT_HOST_J'):

                # If we've exceeded our maximum wait, this isn't a high speed host.
                with m.If(timer == self._CYCLES_2P5_MILLISECONDS):
                    m.next = 'IS_LOW_OR_FULL_SPEED'

                # Once we've seen our J, start timing its duration.
                with m.If(self.line_state == self._LINE_STATE_FS_HS_J):
                    m.next = 'IN_HOST_J'
                    m.d.usb += line_state_time.eq(0)


            # IN_HOST_J: we're seeing a host Chirp K as part of our handshake; we'll
            # time it and see how long it lasts
            with m.State('IN_HOST_J'):

                # If we've exceeded our minimum chirp time, consider this a valid pattern
                # bit, and advance in the pattern.
                with m.If(line_state_time == self._CYCLES_2P5_MICROSECONDS):

                    # If this would complete our third pair, this completes a handshake,
                    # and we've identified a high speed host!
                    with m.If(valid_pairs == 2):
                        m.next = 'IS_HIGH_SPEED'

                    # Otherwise, count the pair as valid, and wait for the next K.
                    with m.Else():
                        m.d.usb += valid_pairs.eq(valid_pairs + 1)
                        m.next = 'AWAIT_HOST_K'

                # If our input has become something other than a K, then
                # we haven't finished our sequence. We'll go back to expecting a K.
                with m.If(self.line_state != self._LINE_STATE_FS_HS_J):
                    m.next = 'AWAIT_HOST_J'

                # Time out if we exceed our maximum allowed duration.
                with m.If(timer == self._CYCLES_2P5_MILLISECONDS):
                    m.next = 'IS_LOW_OR_FULL_SPEED'


            # IS_HIGH_SPEED -- we've completed a high speed handshake, and are ready to
            # switch to high speed signaling
            with m.State('IS_HIGH_SPEED'):

                # Switch to high speed.
                m.d.usb += [
                    timer                    .eq(0),
                    line_state_time          .eq(0),

                    self.current_speed       .eq(USBSpeed.HIGH),
                    self.operating_mode      .eq(UTMIOperatingMode.NORMAL),
                    self.termination_select  .eq(UTMITerminationSelect.HS_NORMAL)
                ]

                m.next = 'HS_NON_RESET'


            # IS_LOW_OR_FULL_SPEED -- we've decided the device is low/full speed (typically
            # because it didn't) complete our high-speed handshake; set it up accordingly.
            with m.State('IS_LOW_OR_FULL_SPEED'):
                m.d.usb += [
                    self.operating_mode      .eq(UTMIOperatingMode.NORMAL),
                    self.termination_select  .eq(UTMITerminationSelect.LS_FS_NORMAL)
                ]

                # If we're operating in low-speed only, drop down to low speed.
                with m.If(self.low_speed_only):
                    m.d.usb += self.current_speed.eq(USBSpeed.LOW),

                # Otherwise, drop down to full speed.
                with m.Else():
                    m.d.usb += self.current_speed.eq(USBSpeed.FULL)

                # Once we know that our reset is complete, move back to our normal, non-reset state.
                with m.If(self.line_state != self._LINE_STATE_SE0):
                    m.next = 'LS_FS_NON_RESET'
                    m.d.usb += [
                        timer.eq(0),
                        line_state_time.eq(0)
                    ]


            # DETECT_HS_SUSPEND -- we were operating at high speed, and just detected an event
            # which is either a reset or a suspend event; we'll now detect which.
            with m.State('DETECT_HS_SUSPEND'):

                # We've just switch from HS signaling to FS signaling.
                # We'll wait a little while for the bus to settle, and then
                # check to see if it's settled to FS idle; or if we still see SE0.
                with m.If(timer == self._CYCLES_200_MICROSECONDS):
                    m.d.usb += timer.eq(0)

                    # If we've resume IDLE, this is suspend. Move to HS suspend.
                    with m.If(self.line_state == self._LINE_STATE_FS_HS_J):
                        m.d.usb += was_hs_pre_suspend.eq(1)
                        m.next = 'SUSPENDED'

                    # Otherwise, this is a reset (or, if K/SE1, we're very confused, and
                    # should re-initialize anyway). Move to the HS reset detect sequence.
                    with m.Else():
                        m.d.comb += self.bus_reset.eq(1)
                        m.next = 'START_HS_DETECTION'


            # SUSPEND -- our device has entered USB suspend; we'll now wait for either a
            # resume or a reset
            with m.State('SUSPENDED'):
                m.d.comb += self.suspended.eq(1)

                # If we see a K state, then we're being resumed.
                is_ls_k = self.low_speed_only  & (self.line_state == self._LINE_STATE_LS_K)
                is_fs_k = ~self.low_speed_only & (self.line_state == self._LINE_STATE_FS_HS_K)
                with m.If(is_ls_k | is_fs_k):
                    m.d.usb  += timer.eq(0)

                    # If we were in high-speed pre-suspend, then resume being in HS.
                    with m.If(was_hs_pre_suspend):
                        m.next = 'IS_HIGH_SPEED'

                    # Otherwise, just resume.
                    with m.Else():
                        m.next = 'LS_FS_NON_RESET'
                        m.d.usb += [
                            timer.eq(0),
                            line_state_time.eq(0)
                        ]


                # If this isn't an SE0, we're not receiving a reset request.
                # Keep our reset counter at zero.
                with m.If(self.line_state != self._LINE_STATE_SE0):
                    m.d.usb += timer.eq(0)


                # If we see an SE0 for > 2.5uS, this is a reset request. [USB 2.0: 7.1.7.5]
                # We'll handle it directly from suspend.
                with m.If(timer == self._CYCLES_2P5_MICROSECONDS):
                    m.d.comb += self.bus_reset.eq(1)
                    m.d.usb  += timer.eq(0)

                    # If we're limited to LS or FS, move to the appropriate state.
                    with m.If(self.low_speed_only | self.full_speed_only):
                        m.next = 'LS_FS_NON_RESET'
                        m.d.usb += [
                            timer.eq(0),
                            line_state_time.eq(0)
                        ]

                    # Otherwise, this could be a high-speed device; enter its reset.
                    with m.Else():
                        m.next = 'START_HS_DETECTION'

        return m
Beispiel #2
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        a = Signal(signed(33))
        b = Signal(signed(33))
        result_ll = Signal(32)
        result_lh = Signal(33)
        result_hl = Signal(33)
        result_hh = Signal(33)
        result_3 = Signal(64)
        result_4 = Signal(64)
        active = Signal(5)
        is_signed = Signal()
        a_is_signed = Signal()
        b_is_signed = Signal()
        low = Signal()

        m.d.sync += [
            is_signed.eq(a_is_signed ^ b_is_signed),
            active.eq(Cat(self.valid & (active == 0), active)),
            low.eq(self.op == Funct3.MUL)
        ]
        # ----------------------------------------------------------------------
        # fist state
        m.d.comb += [
            a_is_signed.eq((
                (self.op == Funct3.MULH) | (self.op == Funct3.MULHSU))
                           & self.dat1[-1]),
            b_is_signed.eq((self.op == Funct3.MULH) & self.dat2[-1])
        ]
        m.d.sync += [
            a.eq(Mux(a_is_signed, -Cat(self.dat1, 1), self.dat1)),
            b.eq(Mux(b_is_signed, -Cat(self.dat2, 1), self.dat2)),
        ]
        # ----------------------------------------------------------------------
        # second state
        m.d.sync += [
            result_ll.eq(a[0:16] * b[0:16]),
            result_lh.eq(a[0:16] * b[16:33]),
            result_hl.eq(a[16:33] * b[0:16]),
            result_hh.eq(a[16:33] * b[16:33])
        ]
        # ----------------------------------------------------------------------
        # third state
        m.d.sync += [
            result_3.eq(
                Cat(result_ll, result_hh) +
                Cat(Repl(0, 16), (result_lh + result_hl)))
        ]
        # ----------------------------------------------------------------------
        # fourth state
        m.d.sync += [
            result_4.eq(Mux(is_signed, -result_3, result_3)),
            self.result.eq(Mux(low, result_4[:32], result_4[32:64]))
        ]
        m.d.comb += self.ready.eq(active[-1])

        return m
Beispiel #3
0
    def elaborate(self, platform):
        m = Module()

        # Create our core, single-byte-wide endpoint, and attach it directly to our interface.
        m.submodules.stream_ep = stream_ep = USBStreamInEndpoint(
            endpoint_number=self._endpoint_number,
            max_packet_size=self._max_packet_size
        )
        stream_ep.interface = self.interface

        # Create semantic aliases for byte-wise and word-wise streams;
        # so the code below reads more clearly.
        byte_stream = stream_ep.stream
        word_stream = self.stream

        # We'll put each word to be sent through an shift register
        # that shifts out words a byte at a time.
        data_shift = Signal.like(word_stream.payload)

        # Latched versions of our first and last signals.
        first_latched = Signal()
        last_latched  = Signal()

        # Count how many bytes we have left to send.
        bytes_to_send = Signal(range(0, self._byte_width + 1))

        # Always provide our inner transmitter with the least byte of our shift register.
        m.d.comb += byte_stream.payload.eq(data_shift[0:8])


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

            # IDLE: transmitter is waiting for input
            with m.State("IDLE"):
                m.d.comb += word_stream.ready.eq(1)

                # Once we get a send request, fill in our shift register, and start shifting.
                with m.If(word_stream.valid):
                    m.d.usb += [
                        data_shift         .eq(word_stream.payload),
                        first_latched      .eq(word_stream.first),
                        last_latched       .eq(word_stream.last),

                        bytes_to_send      .eq(self._byte_width - 1),
                    ]
                    m.next = "TRANSMIT"


            # TRANSMIT: actively send each of the bytes of our word
            with m.State("TRANSMIT"):
                m.d.comb += byte_stream.valid.eq(1)

                # Once the byte-stream is accepting our input...
                with m.If(byte_stream.ready):
                    is_first_byte = (bytes_to_send == self._byte_width - 1)
                    is_last_byte  = (bytes_to_send == 0)

                    # Pass through our First and Last signals, but only on the first and
                    # last bytes of our word, respectively.
                    m.d.comb += [
                        byte_stream.first  .eq(first_latched & is_first_byte),
                        byte_stream.last   .eq(last_latched  & is_last_byte)
                    ]

                    # ... if we have bytes left to send, move to the next one.
                    with m.If(bytes_to_send > 0):
                        m.d.usb += [
                            bytes_to_send .eq(bytes_to_send - 1),
                            data_shift    .eq(data_shift[8:]),
                        ]

                    # Otherwise, complete the frame.
                    with m.Else():
                        m.d.comb += word_stream.ready.eq(1)

                        # If we still have data to send, move to the next byte...
                        with m.If(self.stream.valid):
                            m.d.usb += [
                                data_shift     .eq(word_stream.payload),
                                first_latched  .eq(word_stream.first),
                                last_latched   .eq(word_stream.last),

                                bytes_to_send  .eq(self._byte_width - 1),
                            ]

                        # ... otherwise, move to our idle state.
                        with m.Else():
                            m.next = "IDLE"


        return m
 def __init__(self):
     self.input = Signal(9)
     self.output = Signal()
Beispiel #5
0
 def __init__(self):
     self.a = Signal()
Beispiel #6
0
    def elaborate(self, platform):
        m = Module()


        #
        # Core ROM.
        #

        data_length = len(self.data)

        rom = Memory(width=self.data_width, depth=data_length, init=self.data)
        m.submodules.rom_read_port = rom_read_port = rom.read_port()

        # Register that stores our current position in the stream.
        position_in_stream = Signal(range(0, data_length))

        # Track when we're on the first and last packet.
        on_first_packet = position_in_stream == 0
        on_last_packet  = \
            (position_in_stream == (data_length - 1))      | \
            (position_in_stream == (self.max_length - 1))

        m.d.comb += [
            # Always drive the stream from our current memory output...
            self.stream.payload  .eq(rom_read_port.data),

            ## ... and base First and Last based on our current position in the stream.
            self.stream.first    .eq(on_first_packet & self.stream.valid),
            self.stream.last     .eq(on_last_packet  & self.stream.valid)
        ]



        #
        # Controller.
        #
        with m.FSM(domain=self.domain) as fsm:
            m.d.comb += self.stream.valid.eq(fsm.ongoing('STREAMING'))

            # IDLE -- we're not actively transmitting.
            with m.State('IDLE'):

                # Keep ourselves at the beginning of the stream, but don't yet count.
                m.d.sync += position_in_stream.eq(0)

                # Once the user requests that we start, move to our stream being valid.
                with m.If(self.start & (self.max_length > 0)):
                    m.next = 'STREAMING'


            # STREAMING -- we're actively transmitting data
            with m.State('STREAMING'):
                m.d.comb += [
                    rom_read_port.addr  .eq(position_in_stream)
                ]

                # If the current data byte is accepted, move past it.
                with m.If(self.stream.ready):

                    should_continue = \
                        ((position_in_stream + 1) < self.max_length) & \
                        ((position_in_stream + 1) < data_length)

                    # If there's still data left to transmit, move forward.
                    with m.If(should_continue):
                        m.d.sync += position_in_stream.eq(position_in_stream + 1)
                        m.d.comb += rom_read_port.addr.eq(position_in_stream + 1)

                    # Otherwise, we've finished streaming. Return to IDLE.
                    with m.Else():
                        m.next = 'DONE'

            # DONE -- report our completion; and then return to idle
            with m.State('DONE'):
                m.d.comb += self.done.eq(1)
                m.next = 'IDLE'


        # Convert our sync domain to the domain requested by the user, if necessary.
        if self.domain != "sync":
            m = DomainRenamer({"sync": self.domain})(m)

        return m
Beispiel #7
0
    def elaborate(self, platform):

        m = Module()
        spi = self.spi

        sample_edge = Fell(spi.sck)

        # Bit counter: counts the number of bits received.
        max_bit_count = max(self.word_size, self.command_size)
        bit_count = Signal(range(0, max_bit_count + 1))

        # Shift registers for our command and data.
        current_command = Signal.like(self.command)
        current_word = Signal.like(self.word_received)

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

        with m.FSM() as fsm:
            m.d.comb += [
                self.idle.eq(fsm.ongoing('IDLE')),
                self.stalled.eq(fsm.ongoing('STALL')),
            ]

            # STALL: entered when we can't accept new bits -- either when
            # CS starts asserted, or when we've received more data than expected.
            with m.State("STALL"):

                # Wait for CS to clear.
                with m.If(~spi.cs):
                    m.next = 'IDLE'

            # We ignore all data until chip select is asserted, as that data Isn't For Us (TM).
            # We'll spin and do nothing until the bus-master addresses us.
            with m.State('IDLE'):
                m.d.sync += bit_count.eq(0)

                with m.If(spi.cs):
                    m.next = 'RECEIVE_COMMAND'

            # Once CS is low, we'll shift in our command.
            with m.State('RECEIVE_COMMAND'):

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

                # Continue shifting in data until we have a full command.
                with m.If(bit_count < self.command_size):
                    with m.If(sample_edge):
                        m.d.sync += [
                            bit_count.eq(bit_count + 1),
                            current_command.eq(
                                Cat(spi.sdi, current_command[:-1]))
                        ]

                # ... and then pass that command out to our controller.
                with m.Else():
                    m.d.sync += [
                        bit_count.eq(0),
                        self.command_ready.eq(1),
                        self.command.eq(current_command)
                    ]
                    m.next = 'PROCESSING'

            # Give our controller a wait state to prepare any response they might want to...
            with m.State('PROCESSING'):
                m.next = 'LATCH_OUTPUT'

            # ... and then latch in the response to transmit.
            with m.State('LATCH_OUTPUT'):
                m.d.sync += current_word.eq(self.word_to_send)
                m.next = 'SHIFT_DATA'

            # Finally, exchange data.
            with m.State('SHIFT_DATA'):

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

                m.d.sync += spi.sdo.eq(current_word[-1])

                # Continue shifting data until we have a full word.
                with m.If(bit_count < self.word_size):
                    with m.If(sample_edge):
                        m.d.sync += [
                            bit_count.eq(bit_count + 1),
                            current_word.eq(Cat(spi.sdi, current_word[:-1]))
                        ]

                # ... and then output that word on our bus.
                with m.Else():
                    m.d.sync += [
                        bit_count.eq(0),
                        self.word_complete.eq(1),
                        self.word_received.eq(current_word)
                    ]

                    # Stay in the stall state until CS is de-asserted.
                    m.next = 'STALL'

        return m
Beispiel #8
0
    def elaborate(self, platform):
        phase = Signal(self.phase_depth)
        note = Signal.like(self.note_in.i_data.note)
        mod = Signal.like(self.mod_in)
        pw = Signal.like(self.pw_in)
        octave = Signal(range(OCTAVES))
        step = Signal(range(STEPS))
        base_inc = Signal(self.inc_depth)
        step_incs = Array(
            [Signal.like(base_inc, reset=inc) for inc in self._base_incs])
        inc = Signal.like(phase)
        pulse_sample = Signal.like(self.pulse_out.o_data)
        saw_sample = Signal.like(self.saw_out.o_data)

        m = Module()
        with m.If(self.sync_in):
            m.d.sync += [
                phase.eq(0),
                # self.rdy_out.eq(False),
            ]

        m.d.comb += [
            self.note_in.o_ready.eq(True),
        ]
        with m.If(self.note_in.received()):
            m.d.sync += [
                note.eq(self.note_in.i_data.note),
                octave.eq(div12(self.note_in.i_data.note)),
            ]
        # Calculate pulse wave edges.  The pulse must rise and fall
        # exactly once per cycle.
        prev_msb = Signal()
        new_cycle = Signal()
        pulse_up = Signal()
        up_latch = Signal()
        pw8 = Cat(pw, Const(0, unsigned(1)))
        m.d.sync += [
            prev_msb.eq(phase[-1]),
        ]
        m.d.comb += [
            new_cycle.eq(~phase[-1] & prev_msb),
            # Widen pulse to one sample period minimum.
            pulse_up.eq(new_cycle | (up_latch & (phase[-8:] <= pw8))),
        ]
        m.d.sync += [
            up_latch.eq((new_cycle | up_latch) & pulse_up),
        ]

        with m.FSM():

            with m.State(FSM.START):
                m.d.sync += [
                    # note.eq(self.note_in),
                    mod.eq(self.mod_in),
                    pw.eq(self.pw_in),
                    # octave.eq(div12(self.note_in)),
                ]
                m.next = FSM.MODULUS

            with m.State(FSM.MODULUS):
                m.d.sync += [
                    step.eq(note - mul12(octave)),
                ]
                m.next = FSM.LOOKUP

            with m.State(FSM.LOOKUP):
                m.d.sync += [
                    base_inc.eq(step_incs[step]),
                ]
                # m.next = FSM.MODULATE
                m.next = FSM.SHIFT

            # with m.State(FSM.MODULATE):
            #     ...
            #     m.next = FSM.SHIFT

            with m.State(FSM.SHIFT):
                m.d.sync += [
                    inc.eq((base_inc << octave)[-self.shift:]),
                ]
                m.next = FSM.ADD

            with m.State(FSM.ADD):
                m.d.sync += [
                    phase.eq(phase + inc),
                ]
                m.next = FSM.SAMPLE

            with m.State(FSM.SAMPLE):
                samp_depth = self.saw_out.o_data.shape()[0]
                samp_max = 2**(samp_depth - 1) - 1
                m.d.sync += [
                    pulse_sample.eq(Mux(pulse_up, samp_max, -samp_max)),
                    saw_sample.eq(samp_max - phase[-samp_depth:]),
                ]
                m.next = FSM.EMIT

            with m.State(FSM.EMIT):
                with m.If(self.saw_out.i_ready & self.pulse_out.i_ready):
                    m.d.sync += [
                        self.pulse_out.o_valid.eq(True),
                        self.pulse_out.o_data.eq(pulse_sample),
                        self.saw_out.o_valid.eq(True),
                        self.saw_out.o_data.eq(saw_sample),
                    ]
                    m.next = FSM.START

        with m.If(self.pulse_out.sent()):
            m.d.sync += [
                self.pulse_out.o_valid.eq(False),
            ]
        with m.If(self.saw_out.sent()):
            m.d.sync += [
                self.saw_out.o_valid.eq(False),
            ]
        return m
Beispiel #9
0
    def elaborate(self, platform):
        m = Module()

        # Memory read and write ports.
        m.submodules.read = mem_read_port = self.mem.read_port(domain="ulpi")
        m.submodules.write = mem_write_port = self.mem.write_port(
            domain="ulpi")

        # Store the memory address of our active packet header, which will store
        # packet metadata like the packet size.
        header_location = Signal.like(mem_write_port.addr)
        write_location = Signal.like(mem_write_port.addr)

        # Read FIFO status.
        read_location = Signal.like(mem_read_port.addr)
        fifo_count = Signal.like(mem_read_port.addr, reset=0)
        fifo_new_data = Signal()

        # Current receive status.
        packet_size = Signal(16)

        #
        # Read FIFO logic.
        #
        m.d.comb += [

            # We have data ready whenever there's not data in the FIFO.
            self.data_available.eq(fifo_count != 0),

            # Our data_out is always the output of our read port...
            self.data_out.eq(mem_read_port.data),

            # ... and our read port always reads from our read pointer.
            mem_read_port.addr.eq(read_location),
            self.sampling.eq(mem_write_port.en)
        ]

        # Once our consumer has accepted our current data, move to the next address.
        with m.If(self.next & self.data_available):
            m.d.ulpi += read_location.eq(read_location + 1)

        #
        # FIFO count handling.
        #
        fifo_full = (fifo_count == self.mem_size)

        data_pop = Signal()
        data_push = Signal()
        m.d.comb += [
            data_pop.eq(self.next & self.data_available),
            data_push.eq(fifo_new_data & ~fifo_full)
        ]

        # If we have both a read and a write, don't update the count,
        # as we've both added one and subtracted one.
        with m.If(data_push & data_pop):
            pass

        # Otherwise, add when data's added, and subtract when data's removed.
        with m.Elif(data_push):
            m.d.ulpi += fifo_count.eq(fifo_count + 1)
        with m.Elif(data_pop):
            m.d.ulpi += fifo_count.eq(fifo_count - 1)

        #
        # Core analysis FSM.
        #
        with m.FSM(domain="ulpi") as f:
            m.d.comb += [
                self.overrun.eq(f.ongoing("OVERRUN")),
                self.capturing.eq(f.ongoing("CAPTURE")),
            ]

            # IDLE: wait for an active receive.
            with m.State("IDLE"):

                # Wait until a transmission is active.
                # TODO: add triggering logic?
                with m.If(self.umti.rx_active):
                    m.next = "CAPTURE"
                    m.d.ulpi += [
                        header_location.eq(write_location),
                        write_location.eq(write_location +
                                          self.HEADER_SIZE_BYTES),
                        packet_size.eq(0),
                    ]

                    #with m.If(self.umti.rx_valid):
                    #    m.d.ulpi += [
                    #        fifo_count   .eq(fifo_count + 1),
                    #    write_location   .eq(write_location + self.HEADER_SIZE_BYTES + 1),
                    #        packet_size  .eq(1)
                    #    ]
                    #    m.d.comb += [
                    #        mem_write_port.addr  .eq(write_location + self.HEADER_SIZE_BYTES),
                    #        mem_write_port.data  .eq(self.umti.data_out),
                    #        mem_write_port.en    .eq(1)
                    #    ]

            # Capture data until the packet is complete.
            with m.State("CAPTURE"):

                # Capture data whenever RxValid is asserted.
                m.d.comb += [
                    mem_write_port.addr.eq(write_location),
                    mem_write_port.data.eq(self.umti.data_out),
                    mem_write_port.en.eq(self.umti.rx_valid
                                         & self.umti.rx_active),
                    fifo_new_data.eq(self.umti.rx_valid & self.umti.rx_active)
                ]

                # Advance the write pointer each time we receive a bit.
                with m.If(self.umti.rx_valid & self.umti.rx_active):
                    m.d.ulpi += [
                        write_location.eq(write_location + 1),
                        packet_size.eq(packet_size + 1)
                    ]

                    # If this would be filling up our data memory,
                    # move to the OVERRUN state.
                    with m.If(fifo_count == self.mem_size - 1 -
                              self.HEADER_SIZE_BYTES):
                        m.next = "OVERRUN"

                # If we've stopped receiving, move to the "finalize" state.
                with m.If(~self.umti.rx_active):

                    # Optimization: if we didn't receive any data, there's no need
                    # to create a packet. Clear our header from the FIFO and disarm.
                    with m.If(packet_size == 0):
                        m.next = "IDLE"
                        m.d.ulpi += [write_location.eq(header_location)]
                    with m.Else():
                        m.next = "EOP_1"

            # EOP: handle the end of the relevant packet.
            with m.State("EOP_1"):

                # Now that we're done, add the header to the start of our packet.
                # This will take two cycles, currently, as we're using a 2-byte header,
                # but we only have an 8-bit write port.
                m.d.comb += [
                    mem_write_port.addr.eq(header_location),
                    mem_write_port.data.eq(packet_size[7:16]),
                    #mem_write_port.data  .eq(0xAA),
                    mem_write_port.en.eq(1),
                    fifo_new_data.eq(1)
                ]
                m.next = "EOP_2"

            with m.State("EOP_2"):

                # Add the second byte of our header.
                # Note that, if this is an adjacent read, we should have
                # just captured our packet header _during_ the stop turnaround.
                m.d.comb += [
                    mem_write_port.addr.eq(header_location + 1),
                    mem_write_port.data.eq(packet_size[0:8]),
                    mem_write_port.en.eq(1),
                    fifo_new_data.eq(1)
                ]

                # Move to the next state, which will either be another capture,
                # or our idle state, depending on whether we have another rx.
                with m.If(self.umti.rx_active):
                    m.next = "CAPTURE"
                    m.d.ulpi += [
                        header_location.eq(write_location),
                        write_location.eq(write_location +
                                          self.HEADER_SIZE_BYTES),
                        packet_size.eq(0),
                    ]

                    # FIXME: capture if rx_valid

                with m.Else():
                    m.next = "IDLE"

            # BABBLE -- handles the case in which we've received a packet beyond
            # the allowable size in the USB spec
            with m.State("BABBLE"):

                # Trap here, for now.
                pass

            with m.State("OVERRUN"):
                # TODO: we should probably set an overrun flag and then emit an EOP, here?

                pass

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

        cpu = Core()
        m.submodules += cpu
        m.domains.ph1 = ph1 = ClockDomain("ph1")
        m.domains.ph2 = ph2 = ClockDomain("ph2", clk_edge="neg")

        # Hook up clocks and reset to pins

        if not SLOWCLK:
            clk1 = platform.request("clk1")
            clk2 = platform.request("clk2")
            rst = platform.request("rst")
            m.d.comb += [
                ph1.rst.eq(rst.i),
                ph2.rst.eq(rst.i),
                ph1.clk.eq(clk1.i),
                ph2.clk.eq(clk2.i),
            ]

        if SLOWCLK:
            clk_freq = platform.default_clk_frequency
            timer = Signal(range(0, int(clk_freq // 2)),
                           reset=int(clk_freq // 2) - 1)
            tick = Signal()
            sync = ClockDomain()

            with m.If(timer == 0):
                m.d.sync += timer.eq(timer.reset)
                m.d.sync += tick.eq(~tick)
            with m.Else():
                m.d.sync += timer.eq(timer - 1)
            m.d.comb += [
                ph1.rst.eq(sync.rst),
                ph2.rst.eq(sync.rst),
                ph1.clk.eq(tick),
                ph2.clk.eq(~tick),
            ]

        # Hook up address lines to pins
        addr = []
        for i in range(16):
            pin = platform.request("addr", i)
            m.d.comb += pin.o.eq(cpu.Addr[i])
            addr.append(pin)

        data = []
        if not FAKEMEM:
            # Hook up data in/out + direction to pins
            for i in range(8):
                pin = platform.request("data", i)
                m.d.comb += pin.o.eq(cpu.Dout[i])
                m.d.ph2 += cpu.Din[i].eq(pin.i)
                data.append(pin)

        if FAKEMEM:
            with m.Switch(cpu.Addr):
                for a, d in mem.items():
                    with m.Case(a):
                        m.d.comb += cpu.Din.eq(d)
                with m.Default():
                    m.d.comb += cpu.Din.eq(0x00)
            for i in range(8):
                pin = platform.request("led", i)
                m.d.comb += pin.o.eq(cpu.Addr[i])

        rw = platform.request("rw")
        m.d.comb += rw.o.eq(cpu.RW)

        nIRQ = platform.request("n_irq")
        nNMI = platform.request("n_nmi")
        m.d.ph2 += cpu.IRQ.eq(~nIRQ)
        m.d.ph2 += cpu.NMI.eq(~nNMI)

        ba = platform.request("ba")
        m.d.comb += ba.o.eq(cpu.BA)
        m.d.comb += rw.oe.eq(~cpu.BA)
        for i in range(len(addr)):
            m.d.comb += addr[i].oe.eq(~cpu.BA)
        for i in range(len(data)):
            m.d.comb += data[i].oe.eq(~cpu.BA & ~cpu.RW)

        return m
Beispiel #11
0
 def elab(self, m):
     state = Signal(1)
     m.d.sync += state.eq(~state)
Beispiel #12
0
 def __init__(self):
     self.start_run = Signal()
     self.all_output_finished = Signal()
     self.in_store_ready = Signal()
     self.fifo_has_space = Signal()
     self.gate = Signal()
Beispiel #13
0
 def __init__(self, width):
     self.restart = Signal()
     self.en = Signal()
     self.done = Signal()
     self.max = Signal(width)
Beispiel #14
0
 def __init__(self):
     self.start_run = Signal()
     self.in_store_ready = Signal()
     self.fifo_has_space = Signal()
     self.filter_value_words = Signal(
         range(config.FILTER_DATA_TOTAL_WORDS + 1))
     self.input_depth_words = Signal(
         range(config.MAX_PER_PIXEL_INPUT_WORDS + 1))
     self.gate = Signal()
     self.all_output_finished = Signal()
     self.madd_done = Signal()
     self.acc_done = Signal()
     self.pp_done = Signal()
     self.out_word_done = Signal()
Beispiel #15
0
    def elaborate(self, platform):
        m = Module()

        current_address = Signal(6)
        current_write = Signal(8)

        # Keep our control signals low unless explicitly asserted.
        m.d.usb += [
            self.ulpi_out_req.eq(0),
            self.ulpi_stop.eq(0),
            self.done.eq(0)
        ]

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

            # We're busy whenever we're not IDLE; indicate so.
            m.d.comb += self.busy.eq(~fsm.ongoing('IDLE'))

            # IDLE: wait for a request to be made
            with m.State('IDLE'):

                # Apply a NOP whenever we're idle.
                #
                # This doesn't technically help for normal ULPI
                # operation, as the controller should handle this,
                # but it cleans up the output in our tests and allows
                # this unit to be used standalone.
                m.d.usb += self.ulpi_data_out.eq(0)

                # Constantly latch in our arguments while IDLE.
                # We'll stop latching these in as soon as we're busy.
                m.d.usb += [
                    current_address.eq(self.address),
                    current_write.eq(self.write_data)
                ]

                with m.If(self.read_request):
                    m.next = 'START_READ'

                with m.If(self.write_request):
                    m.next = 'START_WRITE'

            #
            # Read handling.
            #

            # START_READ: wait for the bus to be idle, so we can transmit.
            with m.State('START_READ'):

                # Wait for the bus to be idle.
                with m.If(~self.ulpi_dir):
                    m.next = 'SEND_READ_ADDRESS'

                    # Once it is, start sending our command.
                    m.d.usb += [
                        self.ulpi_data_out.eq(self.COMMAND_REG_READ
                                              | self.address),
                        self.ulpi_out_req.eq(1)
                    ]

            # SEND_READ_ADDRESS: Request sending the read address, which we
            # start sending on the next clock cycle. Note that we don't want
            # to come into this state writing, as we need to lead with a
            # bus-turnaround cycle.
            with m.State('SEND_READ_ADDRESS'):
                m.d.usb += self.ulpi_out_req.eq(1)

                # If DIR has become asserted, we're being interrupted.
                # We'll have to restart the read after the interruption is over.
                with m.If(self.ulpi_dir):
                    m.next = 'START_READ'
                    m.d.usb += self.ulpi_out_req.eq(0)

                # If NXT becomes asserted without us being interrupted by
                # DIR, then the PHY has accepted the read. Release our write
                # request, so the next cycle can properly act as a bus turnaround.
                with m.Elif(self.ulpi_next):
                    m.d.usb += [
                        self.ulpi_out_req.eq(0),
                        self.ulpi_data_out.eq(0),
                    ]
                    m.next = 'READ_TURNAROUND'

            # READ_TURNAROUND: wait for the PHY to take control of the ULPI bus.
            with m.State('READ_TURNAROUND'):

                # After one cycle, we should have a data byte ready.
                m.next = 'READ_COMPLETE'

            # READ_COMPLETE: the ULPI read exchange is complete, and the read data is ready.
            with m.State('READ_COMPLETE'):
                m.next = 'IDLE'

                # Latch in the data, and indicate that we have new, valid data.
                m.d.usb += [
                    self.read_data.eq(self.ulpi_data_in),
                    self.done.eq(1)
                ]

            #
            # Write handling.
            #

            # START_WRITE: wait for the bus to be idle, so we can transmit.
            with m.State('START_WRITE'):

                # Wait for the bus to be idle.
                with m.If(~self.ulpi_dir):
                    m.next = 'SEND_WRITE_ADDRESS'

                    # Once it is, start sending our command.
                    m.d.usb += [
                        self.ulpi_data_out.eq(self.COMMAND_REG_WRITE
                                              | self.address),
                        self.ulpi_out_req.eq(1)
                    ]

            # SEND_WRITE_ADDRESS: Continue sending the write address until the
            # target device accepts it.
            with m.State('SEND_WRITE_ADDRESS'):
                m.d.usb += self.ulpi_out_req.eq(1)

                # If DIR has become asserted, we're being interrupted.
                # We'll have to restart the write after the interruption is over.
                with m.If(self.ulpi_dir):
                    m.next = 'START_WRITE'
                    m.d.usb += self.ulpi_out_req.eq(0)

                # Hold our address until the PHY has accepted the command;
                # and then move to presenting the PHY with the value to be written.
                with m.Elif(self.ulpi_next):
                    m.d.usb += self.ulpi_data_out.eq(self.write_data)
                    m.next = 'HOLD_WRITE'

            # Hold the write data on the bus until the device acknowledges it.
            with m.State('HOLD_WRITE'):
                m.d.usb += self.ulpi_out_req.eq(1)

                # Handle interruption.
                with m.If(self.ulpi_dir):
                    m.next = 'START_WRITE'
                    m.d.usb += self.ulpi_out_req.eq(0)

                # Hold the data present until the device has accepted it.
                # Once it has, pulse STP for a cycle to complete the transaction.
                with m.Elif(self.ulpi_next):
                    m.d.usb += [
                        self.ulpi_data_out.eq(0),
                        self.ulpi_out_req.eq(0),
                        self.ulpi_stop.eq(1),
                        self.done.eq(1)
                    ]
                    m.next = 'IDLE'

        return m
Beispiel #16
0
    def elaborate(self, platform):
        m = Module()

        #
        # Delayed input and output.
        #

        if self.in_skew is not None:
            data_in = delay(m, self.bus.dq.i, self.in_skew)
        else:
            data_in = self.bus.dq.i

        if self.out_skew is not None:
            data_out = Signal.like(self.bus.dq.o)
            delay(m, data_out, self.out_skew, out=self.bus.dq.o)
        else:
            data_out = self.bus.dq.o

        #
        # Transaction clock generator.
        #
        advance_clock = Signal()
        reset_clock = Signal()

        if self.clock_skew is not None:
            out_clock = Signal()
            delay(m, out_clock, self.clock_skew, out=self.bus.clk)
        else:
            out_clock = self.bus.clk

        with m.If(reset_clock):
            m.d.fast += out_clock.eq(0)
        with m.Elif(advance_clock):
            m.d.fast += out_clock.eq(~out_clock)

        #
        # Latched control/addressing signals.
        #
        is_read = Signal()
        is_register = Signal()
        current_address = Signal(32)
        is_multipage = Signal()

        #
        # FSM datapath signals.
        #

        # Tracks whether we need to add an extra latency period between our
        # command and the data body.
        extra_latency = Signal()

        # Tracks how many cycles of latency we have remaining between a command
        # and the relevant data stages.
        latency_edges_remaining = Signal(range(0, self.HIGH_LATENCY_EDGES + 1))

        # One cycle delayed version of RWDS.
        # This is used to detect edges in RWDS during reads, which semantically mean
        # we should accept new data.
        last_rwds = Signal.like(self.bus.rwds.i)
        m.d.fast += last_rwds.eq(self.bus.rwds.i)

        # Create a fast-domain version of our 'new data ready' signal.
        new_data_ready = Signal()

        # We need to stretch our internal strobes to two cycles before passing them
        # into the main clock domain.
        stretch_strobe_signal(m,
                              strobe=new_data_ready,
                              output=self.new_data_ready,
                              to_cycles=2,
                              domain=m.d.fast)

        #
        # Core operation FSM.
        #

        # Provide defaults for our control/status signals.
        m.d.fast += [
            advance_clock.eq(1),
            reset_clock.eq(0),
            new_data_ready.eq(0),
            self.bus.cs.eq(1),
            self.bus.rwds.oe.eq(0),
            self.bus.dq.oe.eq(0),
        ]

        with m.FSM(domain='fast') as fsm:
            m.d.comb += self.idle.eq(fsm.ongoing('IDLE'))

            # IDLE state: waits for a transaction request
            with m.State('IDLE'):
                m.d.fast += reset_clock.eq(1)

                # Once we have a transaction request, latch in our control
                # signals, and assert our chip-select.
                with m.If(self.start_transfer):
                    m.next = 'LATCH_RWDS'

                    m.d.fast += [
                        is_read.eq(~self.perform_write),
                        is_register.eq(self.register_space),
                        is_multipage.eq(~self.single_page),
                        current_address.eq(self.address),
                    ]

                with m.Else():
                    m.d.fast += self.bus.cs.eq(0)

            # LATCH_RWDS -- latch in the value of the RWDS signal, which determines
            # our read/write latency. Note that we advance the clock in this state,
            # as our out-of-phase clock signal will output the relevant data before
            # the next edge can occur.
            with m.State("LATCH_RWDS"):
                m.d.fast += extra_latency.eq(self.bus.rwds.i),
                m.next = "SHIFT_COMMAND0"

            # Commands, in order of bytes sent:
            #   - WRBAAAAA
            #     W         => selects read or write; 1 = read, 0 = write
            #      R        => selects register or memory; 1 = register, 0 = memory
            #       B       => selects burst behavior; 0 = wrapped, 1 = linear
            #        AAAAA  => address bits [27:32]
            #
            #   - AAAAAAAA  => address bits [19:27]
            #   - AAAAAAAA  => address bits [11:19]
            #   - AAAAAAAA  => address bits [ 3:16]
            #   - 00000000  => [reserved]
            #   - 00000AAA  => address bits [ 0: 3]

            # SHIFT_COMMANDx -- shift each of our command bytes out
            with m.State('SHIFT_COMMAND0'):
                m.next = 'SHIFT_COMMAND1'

                # Build our composite command byte.
                command_byte = Cat(current_address[27:32], is_multipage,
                                   is_register, is_read)

                # Output our first byte of our command.
                m.d.fast += [data_out.eq(command_byte), self.bus.dq.oe.eq(1)]

            # Note: it's felt that this is more readable with each of these
            # states defined explicitly. If you strongly disagree, feel free
            # to PR a for-loop, here.~

            with m.State('SHIFT_COMMAND1'):
                m.d.fast += [
                    data_out.eq(current_address[19:27]),
                    self.bus.dq.oe.eq(1)
                ]
                m.next = 'SHIFT_COMMAND2'

            with m.State('SHIFT_COMMAND2'):
                m.d.fast += [
                    data_out.eq(current_address[11:19]),
                    self.bus.dq.oe.eq(1)
                ]
                m.next = 'SHIFT_COMMAND3'

            with m.State('SHIFT_COMMAND3'):
                m.d.fast += [
                    data_out.eq(current_address[3:16]),
                    self.bus.dq.oe.eq(1)
                ]
                m.next = 'SHIFT_COMMAND4'

            with m.State('SHIFT_COMMAND4'):
                m.d.fast += [data_out.eq(0), self.bus.dq.oe.eq(1)]
                m.next = 'SHIFT_COMMAND5'

            with m.State('SHIFT_COMMAND5'):
                m.d.fast += [
                    data_out.eq(current_address[0:3]),
                    self.bus.dq.oe.eq(1)
                ]

                # If we have a register write, we don't need to handle
                # any latency. Move directly to our SHIFT_DATA state.
                with m.If(is_register & ~is_read):
                    m.next = 'WRITE_DATA_MSB'

                # Otherwise, react with either a short period of latency
                # or a longer one, depending on what the RAM requested via
                # RWDS.
                with m.Else():
                    m.next = "HANDLE_LATENCY"

                    with m.If(extra_latency):
                        m.d.fast += latency_edges_remaining.eq(
                            self.HIGH_LATENCY_EDGES)
                    with m.Else():
                        m.d.fast += latency_edges_remaining.eq(
                            self.LOW_LATENCY_EDGES)

            # HANDLE_LATENCY -- applies clock edges until our latency period is over.
            with m.State('HANDLE_LATENCY'):
                m.d.fast += latency_edges_remaining.eq(
                    latency_edges_remaining - 1)

                with m.If(latency_edges_remaining == 0):
                    with m.If(is_read):
                        m.next = 'READ_DATA_MSB'
                    with m.Else():
                        m.next = 'WRITE_DATA_MSB'

            # STREAM_DATA_MSB -- scans in or out the first byte of data
            with m.State('READ_DATA_MSB'):

                # If RWDS has changed, the host has just sent us new data.
                with m.If(self.bus.rwds.i != last_rwds):
                    m.d.fast += [self.read_data[8:16].eq(data_in)]
                    m.next = 'READ_DATA_LSB'

            # STREAM_DATA_LSB -- scans in or out the second byte of data
            with m.State('READ_DATA_LSB'):

                # If RWDS has changed, the host has just sent us new data.
                # Sample it, and indicate that we now have a valid piece of new data.
                with m.If(self.bus.rwds.i != last_rwds):
                    m.d.fast += [
                        self.read_data[0:8].eq(data_in),
                        new_data_ready.eq(1)
                    ]

                    # If our controller is done with the transcation, end it.
                    with m.If(self.final_word):
                        m.next = 'RECOVERY'
                        m.d.fast += advance_clock.eq(0)

                    with m.Else():
                        m.next = 'READ_DATA_MSB'

            # RECOVERY state: wait for the required period of time before a new transaction
            with m.State('RECOVERY'):
                m.d.fast += [self.bus.cs.eq(0), advance_clock.eq(0)]

                # TODO: implement recovery
                m.next = 'IDLE'

            # TODO: implement write shift states

            with m.State("WRITE_DATA_MSB"):
                pass

        return m
Beispiel #17
0
    def elaborate(self, platform):
        m = Module()

        # Shortcuts.
        tx = self.interface.tx
        tokenizer = self.interface.tokenizer

        # Grab a copy of the relevant signal that's in our USB domain; synchronizing if we need to.
        if self._signal_domain == "usb":
            target_signal = self.signal
        else:
            target_signal = synchronize(m, self.signal, o_domain="usb")

        # Store a latched version of our signal, captured before we start a transmission.
        latched_signal = Signal.like(self.signal)

        # Grab an byte-indexable reference into our signal.
        bytes_in_signal = (self._width + 7) // 8
        signal_bytes = Array(latched_signal[n * 8:n * 8 + 8]
                             for n in range(bytes_in_signal))

        # Store how many bytes we've transmitted.
        bytes_transmitted = Signal(range(0, bytes_in_signal + 1))

        #
        # Data transmission logic.
        #

        # If this signal is big endian, send them in reading order; otherwise, index our multiplexer in reverse.
        # Note that our signal is captured little endian by default, due the way we use Array() above. If we want
        # big endian; then we'll flip it.
        if self._endianness == "little":
            index_to_transmit = bytes_transmitted
        else:
            index_to_transmit = bytes_in_signal - bytes_transmitted - 1

        # Always transmit the part of the latched signal byte that corresponds to our
        m.d.comb += tx.payload.eq(signal_bytes[index_to_transmit])

        #
        # Core control FSM.
        #

        endpoint_number_matches = (tokenizer.endpoint == self._endpoint_number)
        targeting_endpoint = endpoint_number_matches & tokenizer.is_in
        packet_requested = targeting_endpoint & tokenizer.ready_for_response

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

            # IDLE -- we've not yet gotten an token requesting data. Wait for one.
            with m.State('IDLE'):

                # Once we're ready to send a response...
                with m.If(packet_requested):

                    m.d.usb += [
                        # ... clear our transmit counter ...
                        bytes_transmitted.eq(0),

                        # ... latch in our response...
                        latched_signal.eq(self.signal),
                    ]

                    # ...  and start transmitting it.
                    m.next = "TRANSMIT_RESPONSE"

            # TRANSMIT_RESPONSE -- we're now ready to send our latched response to the host.
            with m.State("TRANSMIT_RESPONSE"):
                is_last_byte = bytes_transmitted + 1 == bytes_in_signal

                # While we're transmitting, our Tx data is valid.
                m.d.comb += [
                    tx.valid.eq(1),
                    tx.first.eq(bytes_transmitted == 0),
                    tx.last.eq(is_last_byte)
                ]

                # Each time we receive a byte, move on to the next one.
                with m.If(tx.ready):
                    m.d.usb += bytes_transmitted.eq(bytes_transmitted + 1)

                    # If this is the last byte to be transmitted, move to waiting for an ACK.
                    with m.If(is_last_byte):
                        m.next = "WAIT_FOR_ACK"

            # WAIT_FOR_ACK -- we've now transmitted our full packet; we need to wait for the host to ACK it
            with m.State("WAIT_FOR_ACK"):

                # If the host does ACK, we're done! Move back to our idle state.
                with m.If(self.interface.handshakes_in.ack):
                    m.d.comb += self.status_read_complete.eq(1)
                    m.d.usb += self.interface.tx_pid_toggle[0].eq(
                        ~self.interface.tx_pid_toggle[0])
                    m.next = "IDLE"

                # If the host starts a new packet without ACK'ing, we'll need to retransmit.
                # Wait for a new IN token.
                with m.If(self.interface.tokenizer.new_token):
                    m.next = "RETRANSMIT"

            # RETRANSMIT -- the host failed to ACK the data we've most recently sent.
            # Wait here for the host to request the data again.
            with m.State("RETRANSMIT"):

                # Once the host does request the data again...
                with m.If(packet_requested):

                    # ... retransmit it, starting from the beginning.
                    m.d.usb += bytes_transmitted.eq(0),
                    m.next = "TRANSMIT_RESPONSE"

        return m
Beispiel #18
0
    def __init__(self,
                 *,
                 bus,
                 strobe_length=2,
                 in_skew=None,
                 out_skew=None,
                 clock_skew=None):
        """
        Parmeters:
            bus           -- The RAM record that should be connected to this RAM chip.
            strobe_length -- The number of fast-clock cycles any strobe should be asserted for.
            data_skews    -- If provided, adds an input delay to each line of the data input.
                             Can be provided as a single delay number, or an interable of eight
                             delays to separately delay each of the input lines.
        """

        self.in_skew = in_skew
        self.out_skew = out_skew
        self.clock_skew = clock_skew

        #
        # I/O port.
        #
        self.bus = bus
        self.reset = Signal()

        # Control signals.
        self.address = Signal(32)
        self.register_space = Signal()
        self.perform_write = Signal()
        self.single_page = Signal()
        self.start_transfer = Signal()
        self.final_word = Signal()

        # Status signals.
        self.idle = Signal()
        self.new_data_ready = Signal()

        # Data signals.
        self.read_data = Signal(16)
        self.write_data = Signal(16)
Beispiel #19
0
 def __init__(self, duration):
     self.duration = duration
     self.i_trg = Signal()
     self.o_pulse = Signal()
Beispiel #20
0
    def __init__(
        self,
        nlines: int,  # number of lines
        nwords: int,  # number of words x line x way
        nways: int,  # number of ways
        start_addr: int = 0,  # start of cacheable region
        end_addr: int = 2**32,  # end of cacheable region
        enable_write: bool = True  # enable writes to cache
    ) -> None:
        # enable write -> data cache
        if nlines == 0 or (nlines & (nlines - 1)):
            raise ValueError(f'nlines must be a power of 2: {nlines}')
        if nwords not in (4, 8, 16):
            raise ValueError(f'nwords must be 4, 8 or 16: {nwords}')
        if nways not in (1, 2):
            raise ValueError(f'nways must be 1 or 2: {nways}')

        self.enable_write = enable_write
        self.nlines = nlines
        self.nwords = nwords
        self.nways = nways
        self.start_addr = start_addr
        self.end_addr = end_addr
        offset_bits = log2_int(nwords)
        line_bits = log2_int(nlines)
        addr_bits = log2_int(end_addr - start_addr, need_pow2=False)
        tag_bits = addr_bits - line_bits - offset_bits - 2  # -2 because word line.
        extra_bits = 32 - tag_bits - line_bits - offset_bits - 2

        self.pc_layout = [('byte', 2), ('offset', offset_bits),
                          ('line', line_bits), ('tag', tag_bits)]
        if extra_bits != 0:
            self.pc_layout.append(('unused', extra_bits))

        # -------------------------------------------------------------------------
        # IO
        self.s1_address = Record(self.pc_layout)
        self.s1_flush = Signal()
        self.s1_valid = Signal()
        self.s1_stall = Signal()
        self.s1_access = Signal()
        self.s2_address = Record(self.pc_layout)
        self.s2_evict = Signal()
        self.s2_valid = Signal()
        self.s2_stall = Signal()
        self.s2_access = Signal()
        self.s2_miss = Signal()
        self.s2_rdata = Signal(32)
        self.s2_re = Signal()
        if enable_write:
            self.s2_wdata = Signal(32)
            self.s2_sel = Signal(4)
            self.s2_we = Signal()

        self.bus_addr = Record(self.pc_layout)
        self.bus_valid = Signal()
        self.bus_last = Signal()
        self.bus_data = Signal(32)
        self.bus_ack = Signal()
        self.bus_err = Signal()

        self.access_cnt = Signal(40)
        self.miss_cnt = Signal(40)
        # snoop bus
        if not enable_write:
            self.dcache_snoop = InternalSnoopPort(
                name='cache_snoop'
            )  # RO cache. Implement the Internal snooping port
Beispiel #21
0
    def elaborate(self, platform):
        m = Module()

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

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

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

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

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

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

        with m.If(chip_selected):

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

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

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

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

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

        return m
Beispiel #22
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        snoop_addr = Record(self.pc_layout)
        snoop_valid = Signal()

        # -------------------------------------------------------------------------
        # Performance counter
        # TODO: connect to CSR's performance counter
        with m.If(~self.s1_stall & self.s1_valid & self.s1_access):
            m.d.sync += self.access_cnt.eq(self.access_cnt + 1)
        with m.If(self.s2_valid & self.s2_miss & ~self.bus_valid
                  & self.s2_access):
            m.d.sync += self.miss_cnt.eq(self.miss_cnt + 1)
        # -------------------------------------------------------------------------

        way_layout = [('data', 32 * self.nwords),
                      ('tag', self.s1_address.tag.shape()), ('valid', 1),
                      ('sel_lru', 1), ('snoop_hit', 1)]
        if self.enable_write:
            way_layout.append(('sel_we', 1))

        ways = Array(
            Record(way_layout, name='way_idx{}'.format(_way))
            for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)

        # Check hit/miss
        way_hit = m.submodules.way_hit = Encoder(self.nways)
        for idx, way in enumerate(ways):
            m.d.comb += way_hit.i[idx].eq((way.tag == self.s2_address.tag)
                                          & way.valid)

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            # Asumiendo que hay un HIT, indicar que la vía que dió hit es en la cual se va a escribir
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

        # set the LRU
        if self.nways == 1:
            # One way: LRU is useless
            lru = Const(0)  # self.nlines
        else:
            # LRU es un vector de N bits, cada uno indicado el set a reemplazar
            # como NWAY es máximo 2, cada LRU es de un bit
            lru = Signal(self.nlines)
            _lru = lru.bit_select(self.s2_address.line, 1)
            write_ended = self.bus_valid & self.bus_ack & self.bus_last  # err ^ ack = = 1
            access_hit = ~self.s2_miss & self.s2_valid & (way_hit.o == _lru)
            with m.If(write_ended | access_hit):
                m.d.sync += _lru.eq(~_lru)

        # read data from the cache
        m.d.comb += self.s2_rdata.eq(ways[way_hit.o].data.word_select(
            self.s2_address.offset, 32))

        # Internal Snoop
        snoop_use_cache = Signal()
        snoop_tag_match = Signal()
        snoop_line_match = Signal()
        snoop_cancel_refill = Signal()
        if not self.enable_write:
            bits_range = log2_int(self.end_addr - self.start_addr,
                                  need_pow2=False)

            m.d.comb += [
                snoop_addr.eq(self.dcache_snoop.addr),  # aux
                snoop_valid.eq(self.dcache_snoop.we & self.dcache_snoop.valid
                               & self.dcache_snoop.ack),
                snoop_use_cache.eq(snoop_addr[bits_range:] == (
                    self.start_addr >> bits_range)),
                snoop_tag_match.eq(snoop_addr.tag == self.s2_address.tag),
                snoop_line_match.eq(snoop_addr.line == self.s2_address.line),
                snoop_cancel_refill.eq(snoop_use_cache & snoop_valid
                                       & snoop_line_match & snoop_tag_match),
            ]
        else:
            m.d.comb += snoop_cancel_refill.eq(0)

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset +
                                                        1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush
                          | snoop_cancel_refill):
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

        # mark the way to use (replace)
        m.d.comb += ways[lru.bit_select(self.s2_address.line,
                                        1)].sel_lru.eq(self.bus_valid)

        # generate for N ways
        for way in ways:
            # create the memory structures for valid, tag and data.
            valid = Signal(self.nlines)  # Valid bits

            tag_m = Memory(width=len(way.tag), depth=self.nlines)  # tag memory
            tag_rp = tag_m.read_port()
            snoop_rp = tag_m.read_port()
            tag_wp = tag_m.write_port()
            m.submodules += tag_rp, tag_wp, snoop_rp

            data_m = Memory(width=len(way.data),
                            depth=self.nlines)  # data memory
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(
                granularity=32
            )  # implica que solo puedo escribir palabras de 32 bits.
            m.submodules += data_rp, data_wp

            # handle valid
            with m.If(self.s1_flush & self.s1_valid):  # flush
                m.d.sync += valid.eq(0)
            with m.Elif(way.sel_lru & self.bus_last
                        & self.bus_ack):  # refill ok
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(1)
            with m.Elif(way.sel_lru & self.bus_err):  # refill error
                m.d.sync += valid.bit_select(self.bus_addr.line, 1).eq(0)
            with m.Elif(self.s2_evict & self.s2_valid
                        & (way.tag == self.s2_address.tag)):  # evict
                m.d.sync += valid.bit_select(self.s2_address.line, 1).eq(0)

            # assignments
            m.d.comb += [
                tag_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                tag_wp.addr.eq(self.bus_addr.line),
                tag_wp.data.eq(self.bus_addr.tag),
                tag_wp.en.eq(way.sel_lru & self.bus_ack & self.bus_last),
                data_rp.addr.eq(
                    Mux(self.s1_stall, self.s2_address.line,
                        self.s1_address.line)),
                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            # El puerto de escritura se multiplexa debido a que la memoria solo puede tener un
            # puerto de escritura.
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we = Signal(len(data_wp.en))
                aux_wdata = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset,
                                             1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset,
                                             1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    # Aux data: no tengo granularidad de byte en el puerto de escritura. Así que para el
                    # caso en el cual el CPU tiene que escribir, hay que construir el dato (wrord) a reemplazar
                    aux_wdata.eq(
                        Cat(
                            Mux(self.s2_sel[0],
                                self.s2_wdata.word_select(0, 8),
                                self.s2_rdata.word_select(0, 8)),
                            Mux(self.s2_sel[1],
                                self.s2_wdata.word_select(1, 8),
                                self.s2_rdata.word_select(1, 8)),
                            Mux(self.s2_sel[2],
                                self.s2_wdata.word_select(2, 8),
                                self.s2_rdata.word_select(2, 8)),
                            Mux(self.s2_sel[3],
                                self.s2_wdata.word_select(3, 8),
                                self.s2_rdata.word_select(3, 8)))),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset,
                                          1).eq(way.sel_lru & self.bus_ack),
                ]

                # --------------------------------------------------------------
                # intenal snoop
                # for FENCE.i instruction
                _match_snoop = Signal()

                m.d.comb += [
                    snoop_rp.addr.eq(snoop_addr.line),  # read tag memory
                    _match_snoop.eq(snoop_rp.data == snoop_addr.tag),
                    way.snoop_hit.eq(snoop_use_cache & snoop_valid
                                     & _match_snoop
                                     & valid.bit_select(snoop_addr.line, 1)),
                ]
                # check is the snoop match a write from this core
                with m.If(way.snoop_hit):
                    m.d.sync += valid.bit_select(snoop_addr.line, 1).eq(0)
                # --------------------------------------------------------------

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

        # Collection that will store each of our descriptor-generation submodules.
        descriptor_generators = {}

        #
        # Figure out the maximum length we're willing to send.
        #
        length = Signal(16)

        # We'll never send more than our MaxPacketSize. This means that we'll want to send a maximum of
        # either our maximum packet length, or the amount of data we have remaining; whichever is less.
        #
        # Note that this doesn't take into account the length of the actual data to be sent; this is handled
        # in the stream generator.
        words_remaining = self.length - self.start_position
        with m.If(words_remaining <= self._max_packet_length):
            m.d.comb += length.eq(words_remaining)
        with m.Else():
            m.d.comb += length.eq(self._max_packet_length)


        #
        # Create our constant-stream generators for each of our descriptors.
        #
        for type_number, index, raw_descriptor in self._descriptors:

            # Create the generator...
            generator = USBDescriptorStreamGenerator(raw_descriptor)
            descriptor_generators[(type_number, index)] = generator

            m.d.comb += [
                generator.max_length     .eq(length),
                generator.start_position .eq(self.start_position)
            ]

            # ... and attach it to this module.
            m.submodules += generator


        #
        # Connect up each of our generators.
        #

        with m.Switch(self.value):

            # Generate a conditional interconnect for each of our items.
            for (type_number, index), generator in descriptor_generators.items():

                # If the value matches the given type number...
                with m.Case(type_number << 8 | index):

                    # ... connect the relevant generator to our output.
                    m.d.comb += generator.stream  .attach(self.tx)
                    m.d.usb += generator.start    .eq(self.start),

            # If none of our descriptors match, stall any request that comes in.
            with m.Case():
                m.d.comb += self.stall.eq(self.start)


        return m
Beispiel #24
0
    def __init__(self, *, ulpi_bus):

        #
        # I/O port.
        #
        self.ulpi = ulpi_bus
        self.register_operation_in_progress = Signal()

        # Optional: signal that allows access to the last RxCmd byte.
        self.last_rx_command = Signal(8)

        self.line_state = Signal(2)
        self.rx_active = Signal()
        self.rx_error = Signal()
        self.host_disconnect = Signal()
        self.id_digital = Signal()
        self.vbus_valid = Signal()
        self.session_valid = Signal()
        self.session_end = Signal()

        # RxActive strobes.
        self.rx_start = Signal()
        self.rx_stop = Signal()
Beispiel #25
0
 def __init__(self):
     super().__init__()
     self.next = Signal()
     self.r_data = Signal(32)
Beispiel #26
0
    def __init__(self):

        #
        # I/O port.
        #

        self.ulpi_data_in = Signal(8)
        self.ulpi_data_out = Signal(8)
        self.ulpi_out_req = Signal()
        self.ulpi_dir = Signal()
        self.ulpi_next = Signal()
        self.ulpi_stop = Signal()

        self.busy = Signal()
        self.address = Signal(6)
        self.done = Signal()

        self.read_request = Signal()
        self.read_data = Signal(8)

        self.write_request = Signal()
        self.write_data = Signal(8)
Beispiel #27
0
    def __init__(self):
        # Control line
        self.enable_sequencer_rom = Signal()

        # Inputs: 9 + 11 decoder
        # Since this is implemented by a ROM, the address lines
        # must be stable in order for the outputs to start becoming
        # stable. This means that if any input address depends on
        # any output data combinatorically, there's a danger of
        # going unstable. Therefore, all address lines must be
        # registered, or come combinatorically from registered data.

        self.memaddr_2_lsb = Signal(2)
        self.branch_cond = Signal()
        self._instr_phase = Signal(2)
        # Only used on instruction phase 1 in BRANCH.
        self.data_z_in_2_lsb0 = Signal()
        self.imm0 = Signal()
        self.rd0 = Signal()
        self.rs1_0 = Signal()

        # Instruction decoding
        self.opcode_select = Signal(OpcodeSelect)  # 4 bits
        self._funct3 = Signal(3)
        self._alu_func = Signal(4)

        ##############
        # Outputs (66 bits total)
        ##############

        # Raised on the last phase of an instruction.
        self.set_instr_complete = Signal()

        # Raised when the exception card should store trap data.
        self.save_trap_csrs = Signal()

        # CSR lines
        self.csr_to_x = Signal()
        self.z_to_csr = Signal()

        # Memory
        self.mem_rd = Signal(reset=1)
        self.mem_wr = Signal()
        # Bytes in memory word to write
        self.mem_wr_mask = Signal(4)

        self._next_instr_phase = Signal(2)

        self._x_reg_select = Signal(InstrReg)  # 2 bits
        self._y_reg_select = Signal(InstrReg)  # 2 bits
        self._z_reg_select = Signal(InstrReg)  # 2 bits

        # -> X
        self.x_mux_select = Signal(SeqMuxSelect)
        self.reg_to_x = Signal()

        # -> Y
        self.y_mux_select = Signal(SeqMuxSelect)
        self.reg_to_y = Signal()

        # -> Z
        self.z_mux_select = Signal(SeqMuxSelect)
        self.alu_op_to_z = Signal(AluOp)  # 4 bits

        # -> PC
        self.pc_mux_select = Signal(SeqMuxSelect)

        # -> tmp
        self.tmp_mux_select = Signal(SeqMuxSelect)

        # -> csr_num
        self._funct12_to_csr_num = Signal()
        self._mepc_num_to_csr_num = Signal()
        self._mcause_to_csr_num = Signal()

        # -> memaddr
        self.memaddr_mux_select = Signal(SeqMuxSelect)

        # -> memdata
        self.memdata_wr_mux_select = Signal(SeqMuxSelect)

        self._const = Signal(ConstSelect)  # select: 4 bits

        self.enter_trap = Signal()
        self.exit_trap = Signal()

        # Signals for next registers
        self.load_trap = Signal()
        self.next_trap = Signal()
        self.load_exception = Signal()
        self.next_exception = Signal()
        self.next_fatal = Signal()
Beispiel #28
0
    def __init__(self, *, register_window, own_register_window=False):
        """
        Parmaeters:
            register_window     -- The ULPI register window to work with.
            own_register_window -- True iff we're the owner of this register window.
                                   Typically, we'll use the register window for a broader controller;
                                   but this can be set to True to indicate that we need to consider this
                                   register window our own, and thus a submodule.
        """

        self.register_window = register_window
        self.own_register_window = own_register_window

        #
        # I/O port
        #
        self.bus_idle = Signal()
        self.xcvr_select = Signal(2, reset=0b01)
        self.term_select = Signal()
        self.op_mode = Signal(2)
        self.suspend = Signal()

        self.id_pullup = Signal()
        self.dp_pulldown = Signal(reset=1)
        self.dm_pulldown = Signal(reset=1)

        self.chrg_vbus = Signal()
        self.dischrg_vbus = Signal()

        self.busy = Signal()

        # Extra/non-UTMI properties.
        self.use_external_vbus_indicator = Signal(reset=1)

        #
        # Internal variables.
        #
        self._register_signals = {}
Beispiel #29
0
    def elaborate(self, platform):
        m = Module()

        stream    = self.stream
        interface = self.interface
        tokenizer = interface.tokenizer

        #
        # Internal state.
        #

        # Stores whether this is the first byte of a transfer. True if the previous byte had its `last` bit set.
        is_first_byte = Signal(reset=1)

        # Stores the data toggle value we expect.
        expected_data_toggle = Signal()

        #
        # Receiver logic.
        #

        # Create a version of our receive stream that has added `first` and `last` signals, which we'll use
        # internally as our main stream.
        m.submodules.boundary_detector = boundary_detector = USBOutStreamBoundaryDetector()
        m.d.comb += [
            interface.rx                   .stream_eq(boundary_detector.unprocessed_stream),
            boundary_detector.complete_in  .eq(interface.rx_complete),
            boundary_detector.invalid_in   .eq(interface.rx_invalid),
        ]

        rx       = boundary_detector.processed_stream
        rx_first = boundary_detector.first
        rx_last  = boundary_detector.last

        # Create a Rx FIFO.
        m.submodules.fifo = fifo = TransactionalizedFIFO(width=10, depth=self._buffer_size, name="rx_fifo", domain="usb")

        # Generate our `first` bit from the most recently transmitted bit.
        # Essentially, if the most recently valid byte was accompanied by an asserted `last`, the next byte
        # should have `first` asserted.
        with m.If(stream.valid & stream.ready):
            m.d.usb += is_first_byte.eq(stream.last)


        #
        # Create some basic conditionals that will help us make decisions.
        #

        endpoint_number_matches  = (tokenizer.endpoint == self._endpoint_number)
        targeting_endpoint       = endpoint_number_matches & tokenizer.is_out

        expected_pid_match       = (interface.rx_pid_toggle == expected_data_toggle)
        sufficient_space         = (fifo.space_available >= self._max_packet_size)

        ping_response_requested  = endpoint_number_matches & tokenizer.is_ping & tokenizer.ready_for_response
        data_response_requested  = targeting_endpoint & tokenizer.is_out & interface.rx_ready_for_response

        okay_to_receive          = targeting_endpoint & sufficient_space & expected_pid_match
        should_skip              = targeting_endpoint & ~expected_pid_match

        m.d.comb += [

            # We'll always populate our FIFO directly from the receive stream; but we'll also include our
            # "short packet detected" signal, as this indicates that we're detecting the last byte of a transfer.
            fifo.write_data[0:8] .eq(rx.payload),
            fifo.write_data[8]   .eq(rx_last),
            fifo.write_data[9]   .eq(rx_first),
            fifo.write_en        .eq(okay_to_receive & rx.next & rx.valid),

            # We'll keep data if our packet finishes with a valid CRC; and discard it otherwise.
            fifo.write_commit    .eq(targeting_endpoint & boundary_detector.complete_out),
            fifo.write_discard   .eq(targeting_endpoint & boundary_detector.invalid_out),

            # We'll ACK each packet if it's received correctly; _or_ if we skipped the packet
            # due to a PID sequence mismatch. If we get a PID sequence mismatch, we assume that
            # we missed a previous ACK from the host; and ACK without accepting data [USB 2.0: 8.6.3].
            interface.handshakes_out.ack  .eq(
                (data_response_requested & okay_to_receive) |
                (ping_response_requested & okay_to_receive) |
                (data_response_requested & should_skip)
            ),

            # We'll NAK any time we want to accept a packet, but we don't have enough room.
            interface.handshakes_out.nak  .eq(
                (data_response_requested & ~okay_to_receive & ~should_skip) |
                (ping_response_requested & ~okay_to_receive)
            ),

            # Our stream data always comes directly out of the FIFO; and is valid
            # henever our FIFO actually has data for us to read.
            stream.valid      .eq(~fifo.empty),
            stream.payload    .eq(fifo.read_data[0:8]),

            # Our `last` bit comes directly from the FIFO; and we know a `first` bit immediately
            # follows a `last` one.
            stream.last       .eq(fifo.read_data[8]),
            stream.first      .eq(fifo.read_data[9]),

            # Move to the next byte in the FIFO whenever our stream is advaced.
            fifo.read_en      .eq(stream.ready),
            fifo.read_commit  .eq(1)
        ]

        # We'll toggle our DATA PID each time we issue an ACK to the host [USB 2.0: 8.6.2].
        with m.If(data_response_requested & okay_to_receive):
            m.d.usb += expected_data_toggle.eq(~expected_data_toggle)


        return m
Beispiel #30
0
    def elaborate(self, platform):
        m = Module()

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

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

        # Create our SPI-connected registers.
        m.submodules.spi_registers = spi_registers = SPIRegisterInterface(7, 8)
        m.d.comb += spi_registers.spi.connect(board_spi)

        # Create our UMTI translator.
        ulpi = platform.request("target_phy")
        m.submodules.umti = umti = UMTITranslator(ulpi=ulpi)

        # Strap our power controls to be in VBUS passthrough by default,
        # on the target port.
        m.d.comb += [
            platform.request("power_a_port").eq(0),
            platform.request("pass_through_vbus").eq(1),
        ]

        # Set up our parameters.
        m.d.comb += [

            # Set our mode to non-driving and to the desired speed.
            umti.op_mode.eq(0b01),
            umti.xcvr_select.eq(self.usb_speed),

            # Disable all of our terminations, as we want to participate in
            # passive observation.
            umti.dm_pulldown.eq(0),
            umti.dm_pulldown.eq(0),
            umti.term_select.eq(0)
        ]

        read_strobe = Signal()

        # Create a USB analyzer, and connect a register up to its output.
        m.submodules.analyzer = analyzer = USBAnalyzer(umti_interface=umti)

        # Provide registers that indicate when there's data ready, and what the result is.
        spi_registers.add_read_only_register(DATA_AVAILABLE,
                                             read=analyzer.data_available)
        spi_registers.add_read_only_register(ANALYZER_RESULT,
                                             read=analyzer.data_out,
                                             read_strobe=read_strobe)

        m.d.comb += [

            # Internal connections.
            analyzer.next.eq(read_strobe),

            # LED indicators.
            platform.request("led", 0).eq(analyzer.capturing),
            platform.request("led", 1).eq(analyzer.data_available),
            platform.request("led", 2).eq(analyzer.overrun),
            platform.request("led", 3).eq(umti.session_valid),
            platform.request("led", 4).eq(umti.rx_active),
            platform.request("led", 5).eq(umti.rx_error),
        ]

        # Return our elaborated module.
        return m