Ejemplo n.º 1
0
    def decode_nrzi(self, m: Module, bit_time: Signal, got_edge: Signal, sync_counter: DividingCounter):
        """Do the actual decoding of the NRZI bitstream"""
        sync = m.d.sync
        bit_counter  = Signal(7)
        # this counter is used to detect a dead signal
        # to determine when to go back to SYNC state
        dead_counter = Signal(8)
        output       = Signal(reset=1)

        # recover ADAT clock
        with m.If(bit_counter <= (bit_time >> 1)):
            m.d.comb += self.recovered_clock_out.eq(1)
        with m.Else():
            m.d.comb += self.recovered_clock_out.eq(0)

        # when the frame decoder got garbage
        # then we need to go back to SYNC state
        with m.If(self.invalid_frame_in):
            sync += [
                sync_counter.reset_in.eq(1),
                bit_counter.eq(0),
                dead_counter.eq(0)
            ]
            m.next = "SYNC"

        sync += bit_counter.eq(bit_counter + 1)
        with m.If(got_edge):
            sync += [
                # latch 1 until we read it in the middle of the bit
                output.eq(1),
                # resynchronize at each bit edge, 1 to compensate
                # for sync delay
                bit_counter.eq(1),
                # when we get an edge, the signal is alive, reset counter
                dead_counter.eq(0)
            ]
        with m.Else():
            sync += dead_counter.eq(dead_counter + 1)

        # wrap the counter
        with m.If(bit_counter == bit_time):
            sync += bit_counter.eq(0)
        # output at the middle of the bit
        with m.Elif(bit_counter == (bit_time >> 1)):
            sync += [
                self.data_out.eq(output),
                self.data_out_en.eq(1), # pulse out_en
                output.eq(0) # edge has been output, wait for new edge
            ]
        with m.Else():
            sync += self.data_out_en.eq(0)

        # when we had no edge for 16 bits worth of time
        # then we go back to sync state
        with m.If(dead_counter >= bit_time << 4):
            sync += dead_counter.eq(0)
            m.next = "SYNC"
Ejemplo n.º 2
0
    def elaborate(self, platform):
        m = Module()

        interface = self.interface
        tokenizer = interface.tokenizer
        tx = interface.tx

        # Counter that stores how many bytes we have left to send.
        bytes_to_send = Signal(range(0, self._max_packet_size + 1), reset=0)

        # True iff we're the active endpoint.
        endpoint_selected = \
            tokenizer.is_in & \
            (tokenizer.endpoint == self._endpoint_number) \

        # Pulses when the host is requesting a packet from us.
        packet_requested = \
            endpoint_selected \
            & tokenizer.ready_for_response

        #
        # Transmit logic
        #

        # Schedule a packet send whenever a packet is requested.
        with m.If(packet_requested):
            m.d.usb += bytes_to_send.eq(self._max_packet_size)

        # Count a byte as send each time the PHY accepts a byte.
        with m.Elif((bytes_to_send != 0) & tx.ready):
            m.d.usb += bytes_to_send.eq(bytes_to_send - 1)

        m.d.comb += [
            # Always send our constant value.
            tx.payload.eq(self._constant),

            # Send bytes, whenever we have them.
            tx.valid.eq(bytes_to_send != 0),
            tx.first.eq(bytes_to_send == self._max_packet_size),
            tx.last.eq(bytes_to_send == 1)
        ]

        #
        # Data-toggle logic
        #

        # Toggle our data pid when we get an ACK.
        with m.If(interface.handshakes_in.ack & endpoint_selected):
            m.d.usb += interface.tx_pid_toggle.eq(~interface.tx_pid_toggle)

        return m
Ejemplo n.º 3
0
    def elaborate(self, platform):
        m = Module()
        m.submodules.ila = self.ila

        transaction_start = Rose(self.spi.cs)

        # Connect up our SPI transciever to our public interface.
        interface = SPIDeviceInterface(word_size=self.bits_per_word,
                                       clock_polarity=self.clock_polarity,
                                       clock_phase=self.clock_phase)
        m.submodules.spi = interface
        m.d.comb += [
            interface.spi.connect(self.spi),

            # Always output the captured sample.
            interface.word_out.eq(self.ila.captured_sample)
        ]

        # Count where we are in the current transmission.
        current_sample_number = Signal(range(0, self.ila.sample_depth))

        # Our first piece of data is latched in when the transaction
        # starts, so we'll move on to sample #1.
        with m.If(self.spi.cs):
            with m.If(transaction_start):
                m.d.sync += current_sample_number.eq(1)

            # From then on, we'll move to the next sample whenever we're finished
            # scanning out a word (and thus our current samples are latched in).
            # This only works correctly because the SPI interface will accept a word
            # more than one clock cycle after the edge which latches the new address
            # to read, allowing the backing memory to have a clock to latch in the
            # correct value.
            with m.Elif(interface.word_accepted):
                m.d.sync += current_sample_number.eq(current_sample_number + 1)

        # Whenever CS is low, we should be providing the very first sample,
        # so reset our sample counter to 0.
        with m.Else():
            m.d.sync += current_sample_number.eq(0)

        # Ensure our ILA module outputs the right sample.
        m.d.sync += [self.ila.captured_sample_number.eq(current_sample_number)]

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

        return m
Ejemplo n.º 4
0
    def elaborate(self, platform):
        m = Module()

        pkt_start = Signal()
        pkt_active = Signal()
        pkt_end = Signal()

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

            for i in range(5):

                with m.State(f"D{i}"):
                    with m.If(self.i_valid):
                        with m.If(self.i_data | self.i_se0):
                            # Receiving '1' or SE0 early resets the packet start counter.
                            m.next = "D0"

                        with m.Else():
                            # Receiving '0' increments the packet start counter.
                            m.next = f"D{i + 1}"

            with m.State("D5"):
                with m.If(self.i_valid):
                    with m.If(self.i_se0):
                        m.next = "D0"
                    # once we get a '1', the packet is active
                    with m.Elif(self.i_data):
                        m.d.comb += pkt_start.eq(1)
                        m.next = "PKT_ACTIVE"

            with m.State("PKT_ACTIVE"):
                m.d.comb += pkt_active.eq(1)
                with m.If(self.i_valid & self.i_se0):
                    m.d.comb += [pkt_active.eq(0), pkt_end.eq(1)]
                    m.next = "D0"

        # pass all of the outputs through a pipe stage
        m.d.comb += [
            self.o_pkt_start.eq(pkt_start),
            self.o_pkt_active.eq(pkt_active),
            self.o_pkt_end.eq(pkt_end),
        ]

        return m
Ejemplo n.º 5
0
    def elaborate(self, platform):
        assert Funct3.SLLI == Funct3.SLL
        assert Funct3.SRL == Funct3.SRLI
        assert Funct3.SRA == Funct3.SRAI
        m = Module()
        with m.Switch(self.funct3):
            with m.Case(Funct3.SLL):
                m.d.comb += self.res.eq(self.src1 << self.shift)
            with m.Case(Funct3.SRL):
                assert Funct3.SRL == Funct3.SRA
                assert Funct7.SRL != Funct7.SRA

                with m.If(self.funct7 == Funct7.SRL):
                    m.d.comb += self.res.eq(self.src1 >> self.shift)
                with m.Elif(self.funct7 == Funct7.SRA):
                    m.d.comb += [
                        self.src1signed.eq(self.src1),
                        self.res.eq(self.src1signed >> self.shift),
                    ]
        return m
Ejemplo n.º 6
0
 def elaborate(self, platform):
     m = Module()
     ac = Signal(self.width+1)
     ac_next = Signal.like(ac)
     temp = Signal.like(ac)
     q1 = Signal(self.width)
     q1_next = Signal.like(q1)
     i = Signal(range(self.width))
     # combinatorial
     with m.If(ac >= self.y):
         m.d.comb += [temp.eq(ac-self.y),
                      Cat(q1_next, ac_next).eq(
                      Cat(1, q1, temp[0:self.width-1]))]
     with m.Else():
         m.d.comb += [Cat(q1_next, ac_next).eq(Cat(q1, ac) << 1)]
     # synchronized
     with m.If(self.start):
         m.d.sync += [self.valid.eq(0), i.eq(0)]
         with m.If(self.y == 0):
             m.d.sync += [self.busy.eq(0),
                          self.dbz.eq(1)]
         with m.Else():
             m.d.sync += [self.busy.eq(1),
                          self.dbz.eq(0),
                          Cat(q1, ac).eq(Cat(Const(0, 1),
                                         self.x, Const(0, self.width)))]
     with m.Elif(self.busy):
         with m.If(i == self.width-1):
             m.d.sync += [self.busy.eq(0),
                          self.valid.eq(1),
                          i.eq(0),
                          self.q.eq(q1_next),
                          self.r.eq(ac_next >> 1)]
         with m.Else():
             m.d.sync += [i.eq(i+1),
                          ac.eq(ac_next),
                          q1.eq(q1_next)]
     return m
Ejemplo n.º 7
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

        data_oe = self.bus.dq.oe
        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.sync += out_clock.eq(0)
        with m.Elif(advance_clock):
            m.d.sync += 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.sync += last_rwds.eq(self.bus.rwds.i)

        # Create a sync-domain version of our 'new data ready' signal.
        new_data_ready = self.new_data_ready

        #
        # Core operation FSM.
        #

        # Provide defaults for our control/status signals.
        m.d.sync += [
            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() as fsm:

            # IDLE state: waits for a transaction request
            with m.State('IDLE'):
                m.d.sync += reset_clock.eq(1)
                m.d.comb += self.idle.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.sync += [
                        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.sync += 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.sync += 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.sync += [data_out.eq(command_byte), data_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.sync += [
                    data_out.eq(current_address[19:27]),
                    data_oe.eq(1)
                ]
                m.next = 'SHIFT_COMMAND2'

            with m.State('SHIFT_COMMAND2'):
                m.d.sync += [
                    data_out.eq(current_address[11:19]),
                    data_oe.eq(1)
                ]
                m.next = 'SHIFT_COMMAND3'

            with m.State('SHIFT_COMMAND3'):
                m.d.sync += [data_out.eq(current_address[3:16]), data_oe.eq(1)]
                m.next = 'SHIFT_COMMAND4'

            with m.State('SHIFT_COMMAND4'):
                m.d.sync += [data_out.eq(0), data_oe.eq(1)]
                m.next = 'SHIFT_COMMAND5'

            with m.State('SHIFT_COMMAND5'):
                m.d.sync += [data_out.eq(current_address[0:3]), data_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.sync += latency_edges_remaining.eq(
                            self.HIGH_LATENCY_EDGES)
                    with m.Else():
                        m.d.sync += 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.sync += 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.sync += 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.sync += [
                        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.sync += advance_clock.eq(0)

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

            # WRITE_DATA_MSB -- write the first of our two bytes of data to the to the PSRAM
            with m.State("WRITE_DATA_MSB"):
                m.d.sync += [
                    data_out.eq(self.write_data[8:16]),
                    data_oe.eq(1),
                ]
                m.next = "WRITE_DATA_LSB"

            # WRITE_DATA_LSB -- write the first of our two bytes of data to the to the PSRAM
            with m.State("WRITE_DATA_LSB"):
                m.d.sync += [
                    data_out.eq(self.write_data[0:8]),
                    data_oe.eq(1),
                ]
                m.next = "WRITE_DATA_LSB"

                # If we just finished a register write, we're done -- there's no need for recovery.
                with m.If(is_register):
                    m.next = 'IDLE'
                    m.d.sync += advance_clock.eq(0)

                with m.Elif(self.final_word):
                    m.next = 'RECOVERY'
                    m.d.sync += advance_clock.eq(0)

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

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

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

        return m
Ejemplo n.º 8
0
    def elaborate(self, platform):
        m = Module()

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

        # 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 data in the FIFO.
            self.stream.valid.eq((fifo_count != 0) & self.idle),

            # Our data_out is always the output of our read port...
            self.stream.payload.eq(mem_read_port.data),
            self.sampling.eq(mem_write_port.en)
        ]

        # Once our consumer has accepted our current data, move to the next address.
        with m.If(self.stream.ready & self.stream.valid):
            m.d.usb += read_location.eq(read_location + 1)
            m.d.comb += mem_read_port.addr.eq(read_location + 1)

        with m.Else():
            m.d.comb += mem_read_port.addr.eq(read_location),

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

        data_pop = Signal()
        data_push = Signal()
        m.d.comb += [
            data_pop.eq(self.stream.ready & self.stream.valid),
            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.usb += fifo_count.eq(fifo_count + 1)
        with m.Elif(data_pop):
            m.d.usb += fifo_count.eq(fifo_count - 1)

        #
        # Core analysis FSM.
        #
        with m.FSM(domain="usb") as f:
            m.d.comb += [
                self.idle.eq(f.ongoing("IDLE")),
                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.utmi.rx_active):
                    m.next = "CAPTURE"
                    m.d.usb += [
                        header_location.eq(write_location),
                        write_location.eq(write_location +
                                          self.HEADER_SIZE_BYTES),
                        packet_size.eq(0),
                    ]

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

                byte_received = self.utmi.rx_valid & self.utmi.rx_active

                # Capture data whenever RxValid is asserted.
                m.d.comb += [
                    mem_write_port.addr.eq(write_location),
                    mem_write_port.data.eq(self.utmi.rx_data),
                    mem_write_port.en.eq(byte_received),
                    fifo_new_data.eq(byte_received),
                ]

                # Advance the write pointer each time we receive a bit.
                with m.If(byte_received):
                    m.d.usb += [
                        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.utmi.rx_active):
                    m.next = "EOP_1"

                    # 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.usb += [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[8:16]),
                    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)
                ]

                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
Ejemplo n.º 9
0
    def elaborate(self, platform):
        m = Module()

        def get_all_resources(name):
            resources = []
            for number in itertools.count():
                try:
                    resources.append(platform.request(name, number))
                except ResourceError:
                    break
            return resources

        if platform and self.top:
            board_spi = platform.request("debug_spi")
            leds = [res.o for res in get_all_resources("led")]
            bldc = platform.request("bldc")
            # connect to signal out
            # ALS ie 0 is lees je hoog, als ie laag is lees je hoog
            m.d.comb += [
                leds[0].eq(bldc.sensor),
                board_spi.sdo.eq(bldc.sensor),
                self.on.eq(board_spi.sdi)
            ]
        else:
            platform = self.platform
            bldc = platform.bldc

        maxcnt = int(platform.laser_var['CRYSTAL_HZ'] /
                     (self.frequency * self.states))
        maxrotations = 30 * self.states * self.frequency
        timer = Signal(maxcnt.bit_length() + 1)
        rotations = Signal(range(maxrotations))

        state = Signal(range(self.states))
        with m.FSM(reset='INIT', name='algo'):
            with m.State('INIT'):
                m.d.sync += rotations.eq(0)
                # with m.If(self.on):
                m.next = 'ROTATION'
            with m.State('ROTATION'):
                # state
                with m.If(timer == maxcnt):
                    m.d.sync += timer.eq(0)
                    # m.d.sync += state.eq(0)
                    with m.If(state == self.states - 1):
                        m.d.sync += state.eq(0)
                    with m.Else():
                        m.d.sync += state.eq(state + 1)
                with m.Else():
                    m.d.sync += timer.eq(timer + 1)
                # duty cycle
                with m.If(rotations == maxrotations):
                    m.d.sync += rotations.eq(maxrotations)
                with m.Else():
                    m.d.sync += rotations.eq(rotations + 1)
                # with m.If(~self.on):
                #     m.next = 'INIT'

        thresh = Signal.like(timer)

        # with m.If(rotations<(10*self.states*self.frequency)):
        m.d.comb += thresh.eq(int(maxcnt * self.dutycyclestart))
        # with m.If(rotations<(10*self.states*self.frequency)):
        #     m.d.comb += thresh.eq(int(maxcnt*self.dutycyclestart))
        # with m.Else():
        #     m.d.comb += thresh.eq(int(maxcnt*self.dutycyclelong))

        # six states and one off state
        with m.If(timer > thresh):
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(0)
            ]
        with m.Elif(state == 0):
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(1),
                bldc.wL.eq(1),
                bldc.wH.eq(0)
            ]
        with m.Elif(state == 1):
            m.d.comb += [
                bldc.uL.eq(1),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(1),
                bldc.wL.eq(0),
                bldc.wH.eq(0)
            ]
        with m.Elif(state == 2):
            m.d.comb += [
                bldc.uL.eq(1),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(1)
            ]
        with m.Elif(state == 3):
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(0),
                bldc.vL.eq(1),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(1)
            ]
        with m.Elif(state == 4):
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(1),
                bldc.vL.eq(1),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(0)
            ]
        with m.Elif(state == 5):
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(1),
                bldc.vL.eq(0),
                bldc.vH.eq(0),
                bldc.wL.eq(1),
                bldc.wH.eq(0)
            ]
        return m
Ejemplo n.º 10
0
    def elaborate(self, platform):
        m = Module()
        # add 1 MHz clock domain
        cntr = Signal(range(self.divider))
        # pos
        max_bits = (self.max_steps << self.bit_shift).bit_length()
        cntrs = Array(
            Signal(signed(max_bits + 1)) for _ in range(len(self.coeff)))
        assert max_bits <= 64
        ticks = Signal(MOVE_TICKS.bit_length())
        if self.top:
            steppers = [res for res in get_all_resources(platform, "stepper")]
            assert len(steppers) != 0
            for idx, stepper in enumerate(steppers):
                m.d.comb += [
                    stepper.step.eq(self.step[idx]),
                    stepper.dir.eq(self.dir[idx])
                ]
        else:
            self.ticks = ticks
            self.cntrs = cntrs

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

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

                m.d.sync += self.busy.eq(0)
            with m.State('WAIT_START'):
                with m.If(self.start):
                    for motor in range(self.motors):
                        coef0 = motor * self.order
                        step_bit = self.bit_shift + 1
                        m.d.sync += [
                            cntrs[coef0].eq(cntrs[coef0][:step_bit]),
                            counter_d[motor].eq(counter_d[motor][:step_bit])
                        ]
                        for degree in range(1, self.order):
                            m.d.sync += cntrs[coef0 + degree].eq(0)
                    m.d.sync += self.busy.eq(1)
                    m.next = 'RUNNING'
                with m.Else():
                    m.d.sync += self.busy.eq(0)
            with m.State('RUNNING'):
                with m.If((ticks < self.ticklimit)
                          & (cntr >= self.divider - 1)):
                    m.d.sync += [ticks.eq(ticks + 1), cntr.eq(0)]
                    for motor in range(self.motors):
                        order = self.order
                        idx = motor * order
                        op3, op2, op1 = 0, 0, 0
                        if order > 2:
                            op3 += 3 * 2 * self.coeff[idx + 2] + cntrs[idx + 2]
                            op2 += cntrs[idx + 2]
                            op1 += self.coeff[idx + 2] + cntrs[idx + 2]
                            m.d.sync += cntrs[idx + 2].eq(op3)
                        if order > 1:
                            op2 += (2 * self.coeff[idx + 1] + cntrs[idx + 1])
                            m.d.sync += cntrs[idx + 1].eq(op2)
                        op1 += (self.coeff[idx + 1] + self.coeff[idx] +
                                cntrs[idx + 1] + cntrs[idx])
                        m.d.sync += cntrs[idx].eq(op1)
                with m.Elif(ticks < self.ticklimit):
                    m.d.sync += cntr.eq(cntr + 1)
                with m.Else():
                    m.d.sync += ticks.eq(0)
                    m.next = 'WAIT_START'
        return m
Ejemplo n.º 11
0
    def elaborate(self, platform):
        m = Module()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return m
Ejemplo n.º 12
0
    def elaborate(self, platform):
        m = Module()
        state = Signal(3)

        if platform and self.top:
            leds = [res.o for res in get_all_resources(platform, "led")]
            for idx in range(len(self.leds)):
                m.d.comb += self.leds[idx].eq(leds[idx])
            bldc = platform.request("bldc")
            m.d.comb += self.enable_prism.eq(1)
            m.d.comb += [
                bldc.uL.eq(self.uL),
                bldc.uH.eq(self.uH),
                bldc.vL.eq(self.vL),
                bldc.vH.eq(self.vH),
                bldc.wL.eq(self.wL),
                bldc.wH.eq(self.wH)
            ]
            m.d.comb += [
                self.hall[0].eq(bldc.sensor0), self.hall[1].eq(bldc.sensor1),
                self.hall[2].eq(bldc.sensor2)
            ]

        for idx in range(len(self.leds)):
            m.d.comb += self.leds[idx].eq(self.hall[idx])

        # tested by trying out all possibilities
        m.d.sync += state.eq(Cat(self.hall[0], self.hall[1], self.hall[2]))

        target = 200000
        max_measurement = target * 10
        measurement = Signal(range(max_measurement))
        timer = Signal().like(measurement)
        statefilter = Signal(3)
        stateold = Signal(3)
        max_delay = 1000
        delay = Signal(range(max_delay))

        # Statefilter
        # The current motor can reach state 0,0,0
        # The measurements of the hall sensors are
        # filtered to prevent this
        with m.If((state >= 1) & (state <= 6)):
            m.d.sync += statefilter.eq(state)

        m.d.sync += stateold.eq(statefilter)

        # PID controller
        step = max_delay // 100
        with m.If((measurement > target) & (delay >= step)):
            m.d.sync += delay.eq(delay - step)
        with m.Elif((measurement < target) & (delay < (max_delay - step))):
            m.d.sync += delay.eq(delay + step)
        with m.Else():
            m.d.sync += delay.eq(0)

        # Measure Cycle
        # Measures the speed of the motor by checking
        # how often state 1 is reached
        with m.If(timer >= max_measurement - 1):
            m.d.sync += [timer.eq(0), measurement.eq(timer)]
        with m.Elif((statefilter == 1) & (stateold != 1)):
            m.d.sync += [measurement.eq(timer), timer.eq(0)]
        with m.Else():
            m.d.sync += timer.eq(timer + 1)

        off = Signal()
        duty = Signal(range(max_delay))

        # Duty cycle
        # Regulates power to the motor by turning it off
        # if larger than duty cycle
        with m.If(duty < max_delay):
            m.d.sync += duty.eq(0)
        with m.Else():
            m.d.sync += duty.eq(duty + 1)

        # Motor On / Off
        with m.If(duty < delay):
            m.d.sync += off.eq(1)
        with m.Else():
            m.d.sync += off.eq(0)

        # https://www.mathworks.com/help/mcb/ref/sixstepcommutation.html
        with m.If((~self.enable_prism) | off):
            m.d.comb += [
                self.uL.eq(0),
                self.uH.eq(0),
                self.vL.eq(0),
                self.vH.eq(0),
                self.wL.eq(0),
                self.wH.eq(0)
            ]
        with m.Elif(statefilter == 1):  # V --> W, 001
            m.d.comb += [
                self.uL.eq(0),
                self.uH.eq(0),
                self.vL.eq(0),
                self.vH.eq(1),
                self.wL.eq(1),
                self.wH.eq(0)
            ]
        with m.Elif(statefilter == 3):  # V --> U, 011
            m.d.comb += [
                self.uL.eq(1),
                self.uH.eq(0),
                self.vL.eq(0),
                self.vH.eq(1),
                self.wL.eq(0),
                self.wH.eq(0)
            ]
        with m.Elif(statefilter == 2):  # W --> U, 010
            m.d.comb += [
                self.uL.eq(1),
                self.uH.eq(0),
                self.vL.eq(0),
                self.vH.eq(0),
                self.wL.eq(0),
                self.wH.eq(1)
            ]
        with m.Elif(statefilter == 6):  # W --> V, 110
            m.d.comb += [
                self.uL.eq(0),
                self.uH.eq(0),
                self.vL.eq(1),
                self.vH.eq(0),
                self.wL.eq(0),
                self.wH.eq(1)
            ]
        with m.Elif(statefilter == 4):  # U --> V, 100
            m.d.comb += [
                self.uL.eq(0),
                self.uH.eq(1),
                self.vL.eq(1),
                self.vH.eq(0),
                self.wL.eq(0),
                self.wH.eq(0)
            ]
        with m.Elif(statefilter == 5):  # U --> W, 101
            m.d.comb += [
                self.uL.eq(0),
                self.uH.eq(1),
                self.vL.eq(0),
                self.vH.eq(0),
                self.wL.eq(1),
                self.wH.eq(0)
            ]
        # with m.Else():         # disabled
        #     m.d.comb += [bldc.uL.eq(0),
        #                  bldc.uH.eq(0),
        #                  bldc.vL.eq(0),
        #                  bldc.vH.eq(0),
        #                  bldc.wL.eq(0),
        #                  bldc.wH.eq(0)]
        return m
Ejemplo n.º 13
0
    def elaborate(self, platform):
        m = Module()

        # Range shortcuts for internal signals.
        address_range = range(0, self.depth + 1)

        #
        # Core internal "backing store".
        #
        memory = Memory(width=self.width, depth=self.depth + 1, name=self.name)
        m.submodules.read_port = read_port = memory.read_port()
        m.submodules.write_port = write_port = memory.write_port()

        # Always connect up our memory's data/en ports to ours.
        m.d.comb += [
            self.read_data.eq(read_port.data),
            write_port.data.eq(self.write_data),
            write_port.en.eq(self.write_en & ~self.full)
        ]

        #
        # Write port.
        #

        # We'll track two pieces of data: our _committed_ write position, and our current un-committed write one.
        # This will allow us to rapidly backtrack to our pre-commit position.
        committed_write_pointer = Signal(address_range)
        current_write_pointer = Signal(address_range)
        m.d.comb += write_port.addr.eq(current_write_pointer)

        # Compute the location for the next write, accounting for wraparound. We'll not assume a binary-sized
        # buffer; so we'll compute the wraparound manually.
        next_write_pointer = Signal.like(current_write_pointer)
        with m.If(current_write_pointer == self.depth):
            m.d.comb += next_write_pointer.eq(0)
        with m.Else():
            m.d.comb += next_write_pointer.eq(current_write_pointer + 1)

        # If we're writing to the fifo, update our current write position.
        with m.If(self.write_en & ~self.full):
            m.d.sync += current_write_pointer.eq(next_write_pointer)

        # If we're committing a FIFO write, update our committed position.
        with m.If(self.write_commit):
            m.d.sync += committed_write_pointer.eq(current_write_pointer)

        # If we're discarding our current write, reset our current position,
        with m.If(self.write_discard):
            m.d.sync += current_write_pointer.eq(committed_write_pointer)

        #
        # Read port.
        #

        # We'll track two pieces of data: our _committed_ read position, and our current un-committed read one.
        # This will allow us to rapidly backtrack to our pre-commit position.
        committed_read_pointer = Signal(address_range)
        current_read_pointer = Signal(address_range)

        # Compute the location for the next read, accounting for wraparound. We'll not assume a binary-sized
        # buffer; so we'll compute the wraparound manually.
        next_read_pointer = Signal.like(current_read_pointer)
        with m.If(current_read_pointer == self.depth):
            m.d.comb += next_read_pointer.eq(0)
        with m.Else():
            m.d.comb += next_read_pointer.eq(current_read_pointer + 1)

        # Our memory always takes a single cycle to provide its read output; so we'll update its address
        # "one cycle in advance". Accordingly, if we're about to advance the FIFO, we'll use the next read
        # address as our input. If we're not, we'll use the current one.
        with m.If(self.read_en & ~self.empty):
            m.d.comb += read_port.addr.eq(next_read_pointer)
        with m.Else():
            m.d.comb += read_port.addr.eq(current_read_pointer)

        # If we're reading from our the fifo, update our current read position.
        with m.If(self.read_en & ~self.empty):
            m.d.sync += current_read_pointer.eq(next_read_pointer)

        # If we're committing a FIFO write, update our committed position.
        with m.If(self.read_commit):
            m.d.sync += committed_read_pointer.eq(current_read_pointer)

        # If we're discarding our current write, reset our current position,
        with m.If(self.read_discard):
            m.d.sync += current_read_pointer.eq(committed_read_pointer)

        #
        # FIFO status.
        #

        # Our FIFO is empty if our read and write pointers are in the same. We'll use the current
        # read position (which leads ahead) and the committed write position (which lags behind).
        m.d.comb += self.empty.eq(
            current_read_pointer == committed_write_pointer)

        # For our space available, we'll use the current write position (which leads ahead) and our committed
        # read position (which lags behind). This yields two cases: one where the buffer isn't wrapped around,
        # and one where it is.
        with m.If(self.full):
            m.d.comb += self.space_available.eq(0)
        with m.Elif(committed_read_pointer <= current_write_pointer):
            m.d.comb += self.space_available.eq(self.depth -
                                                (current_write_pointer -
                                                 committed_read_pointer))
        with m.Else():
            m.d.comb += self.space_available.eq(committed_read_pointer -
                                                current_write_pointer - 1)

        # Our FIFO is full if we don't have any space available.
        m.d.comb += self.full.eq(next_write_pointer == committed_read_pointer)

        # If we're not supposed to be in the sync domain, rename our sync domain to the target.
        if self.domain != "sync":
            m = DomainRenamer({"sync": self.domain})(m)

        return m
Ejemplo n.º 14
0
    def elaborate(self, platform):
        m = Module()

        # Create the component parts of our ULPI interfacing hardware.
        m.submodules.register_window     = register_window     = ULPIRegisterWindow()
        m.submodules.control_translator  = control_translator  = ULPIControlTranslator(register_window=register_window)
        m.submodules.rxevent_decoder     = rxevent_decoder     = ULPIRxEventDecoder(ulpi_bus=self.ulpi)
        m.submodules.transmit_translator = transmit_translator = ULPITransmitTranslator()

        # If we're choosing to honor any registers defined in the platform file, apply those
        # before continuing with elaboration.
        if self.use_platform_registers and hasattr(platform, 'ulpi_extra_registers'):
            for address, value in platform.ulpi_extra_registers.items():
                self.add_extra_register(address, value)

        # Some platforms may need to have a raw clock domain for their I/O; e.g. if they need
        # to do some simple processing for their internal clock domain.
        if self.handle_clocking and hasattr(platform, 'ulpi_raw_clock_domain'):
            raw_clock_domain = platform.ulpi_raw_clock_domain
        else:
            raw_clock_domain = 'usb'


        # Add any extra registers provided by the user to our control translator.
        for address, values in self._extra_registers.items():
            control_translator.add_composite_register(m, address, values['value'], reset_value=values['default'])

        # Keep track of when any of our components are busy
        any_busy = \
            register_window.busy     | \
            transmit_translator.busy | \
            control_translator.busy  | \
            self.ulpi.dir


        # If we're handling ULPI clocking, do so.
        if self.handle_clocking:

            # We can't currently handle bidirectional clock lines, as we don't know if they
            # should be used in input or output modes.
            if hasattr(self.ulpi.clk, 'oe'):
                raise TypeError("ULPI records with bidirectional clock lines require manual handling.")

            # Just Input (TM) and Just Output (TM) clocks are simpler: we know how to drive them.
            elif hasattr(self.ulpi.clk, 'o'):
                m.d.comb += self.ulpi.clk.eq(ClockSignal(raw_clock_domain))
            elif hasattr(self.ulpi.clk, 'i'):
                m.d.comb += ClockSignal(raw_clock_domain).eq(self.ulpi.clk)

            # Clocks that don't seem to be I/O pins aren't what we're expecting; fail out.
            else:
                raise TypeError(f"ULPI `clk` was an unexpected type {type(self.ulpi.clk)}." \
                    " You may need to handle clocking manually.")


        # Hook up our reset signal iff our ULPI bus has one.
        if hasattr(self.ulpi, 'rst'):
            m.d.comb += self.ulpi.rst  .eq(ResetSignal(raw_clock_domain)),


        # Connect our ULPI control signals to each of our subcomponents.
        m.d.comb += [

            # Drive the bus whenever the target PHY isn't.
            self.ulpi.data.oe            .eq(~self.ulpi.dir),

            # Generate our busy signal.
            self.busy                    .eq(any_busy),

            # Connect our data inputs to the event decoder.
            # Note that the event decoder is purely passive.
            rxevent_decoder.register_operation_in_progress.eq(register_window.busy),
            self.last_rx_command          .eq(rxevent_decoder.last_rx_command),

            # Connect our inputs to our transmit translator.
            transmit_translator.ulpi_nxt  .eq(self.ulpi.nxt),
            transmit_translator.op_mode   .eq(self.op_mode),
            transmit_translator.bus_idle  .eq(~control_translator.busy & ~self.ulpi.dir),
            transmit_translator.tx_data   .eq(self.tx_data),
            transmit_translator.tx_valid  .eq(self.tx_valid),
            self.tx_ready                 .eq(transmit_translator.tx_ready),

            # Connect our inputs to our control translator / register window.
            control_translator.bus_idle   .eq(~transmit_translator.busy),
            register_window.ulpi_data_in  .eq(self.ulpi.data.i),
            register_window.ulpi_dir      .eq(self.ulpi.dir),
            register_window.ulpi_next     .eq(self.ulpi.nxt),
        ]

        # Control our the source of our ULPI data output.
        # If a transmit request is active, prioritize that over
        # any register reads/writes.
        with m.If(transmit_translator.ulpi_out_req):
            m.d.comb += [
                self.ulpi.data.o  .eq(transmit_translator.ulpi_data_out),
                self.ulpi.stp     .eq(transmit_translator.ulpi_stp)
            ]
        # Otherwise, yield control to the register handler.
        # This is a slight optimization: since it properly generates NOPs
        # while not in use, we can let it handle idle, as well, saving a mux.
        with m.Else():
            m.d.comb += [
                self.ulpi.data.o  .eq(register_window.ulpi_data_out),
                self.ulpi.stp     .eq(register_window.ulpi_stop)
            ]


        # Connect our RxEvent status signals from our RxEvent decoder.
        for signal_name, _ in self.RXEVENT_STATUS_SIGNALS:
            signal = getattr(rxevent_decoder, signal_name)
            m.d.comb += self.__dict__[signal_name].eq(signal)

        # Connect our control signals through the control translator.
        for signal_name, _ in self.CONTROL_SIGNALS:
            signal = getattr(control_translator, signal_name)
            m.d.comb += signal.eq(self.__dict__[signal_name])


        # RxActive handler:
        # A transmission starts when DIR goes high with NXT, or when an RxEvent indicates
        # a switch from RxActive = 0 to RxActive = 1. A transmission stops when DIR drops low,
        # or when the RxEvent RxActive bit drops from 1 to 0, or an error occurs.A
        dir_rising_edge = Rose(self.ulpi.dir.i, domain="usb")
        dir_based_start = dir_rising_edge & self.ulpi.nxt


        with m.If(~self.ulpi.dir | rxevent_decoder.rx_stop):
            # TODO: this should probably also trigger if RxError
            m.d.usb += self.rx_active.eq(0)
        with m.Elif(dir_based_start | rxevent_decoder.rx_start):
            m.d.usb += self.rx_active.eq(1)


        # Data-out: we'll connect this almost direct through from our ULPI
        # interface, as it's essentially the same as in the UTMI spec. We'll
        # add a one cycle processing delay so it matches the rest of our signals.

        # RxValid: equivalent to NXT whenever a Rx is active.
        m.d.usb += [
            self.rx_data   .eq(self.ulpi.data.i),
            self.rx_valid  .eq(self.ulpi.nxt & self.rx_active)
        ]

        return m
Ejemplo n.º 15
0
    def elaborate(self, platform):
        m = Module()

        #
        # Transciever state.
        #


        # Handle our PID-sequence reset.
        # Note that we store the _inverse_ of our data PID, as we'll toggle our DATA PID
        # before sending.
        with m.If(self.reset_sequence):
            m.d.usb += self.data_pid.eq(~self.start_with_data1)

        #
        # Transmit buffer.
        #
        # Our USB connection imposed a few requirements on our stream:
        # 1) we must be able to transmit packets at a full rate; i.e.
        #    must be asserted from the start to the end of our transfer; and
        # 2) we must be able to re-transmit data if a given packet is not ACK'd.
        #
        # Accordingly, we'll buffer a full USB packet of data, and then transmit
        # it once either a) our buffer is full, or 2) the transfer ends (last=1).
        #
        # This implementation is double buffered; so a buffer fill can be pipelined
        # with a transmit.
        #

        # We'll create two buffers; so we can fill one as we empty the other.
        buffer = Array(Memory(width=8, depth=self._max_packet_size, name=f"transmit_buffer_{i}") for i in range(2))
        buffer_write_ports = Array(buffer[i].write_port(domain="usb") for i in range(2))
        buffer_read_ports  = Array(buffer[i].read_port(domain="usb") for i in range(2))

        m.submodules.read_port_0,  m.submodules.read_port_1  = buffer_read_ports
        m.submodules.write_port_0, m.submodules.write_port_1 = buffer_write_ports

        # Create values equivalent to the buffer numbers for our read and write buffer; which switch
        # whenever we swap our two buffers.
        write_buffer_number =  self.buffer_toggle
        read_buffer_number  = ~self.buffer_toggle

        # Create a shorthand that refers to the buffer to be filled; and the buffer to send from.
        # We'll call these the Read and Write buffers.
        buffer_write = buffer_write_ports[write_buffer_number]
        buffer_read  = buffer_read_ports[read_buffer_number]

        # Buffer state tracking:
        # - Our ``fill_count`` keeps track of how much data is stored in a given buffer.
        # - Our ``stream_ended`` bit keeps track of whether the stream ended while filling up
        #   the given buffer. This indicates that the buffer cannot be filled further; and, when
        #   ``generate_zlps`` is enabled, is used to determine if the given buffer should end in
        #   a short packet; which determines whether ZLPs are emitted.
        buffer_fill_count   = Array(Signal(range(0, self._max_packet_size + 1)) for _ in range(2))
        buffer_stream_ended = Array(Signal(name=f"stream_ended_in_buffer{i}") for i in range(2))

        # Create shortcuts to active fill_count / stream_ended signals for the buffer being written.
        write_fill_count   = buffer_fill_count[write_buffer_number]
        write_stream_ended = buffer_stream_ended[write_buffer_number]

        # Create shortcuts to the fill_count / stream_ended signals for the packet being sent.
        read_fill_count   = buffer_fill_count[read_buffer_number]
        read_stream_ended = buffer_stream_ended[read_buffer_number]

        # Keep track of our current send position; which determines where we are in the packet.
        send_position = Signal(range(0, self._max_packet_size + 1))

        # Shortcut names.
        in_stream  = self.transfer_stream
        out_stream = self.packet_stream


        # Use our memory's two ports to capture data from our transfer stream; and two emit packets
        # into our packet stream. Since we'll never receive to anywhere else, or transmit to anywhere else,
        # we can just unconditionally connect these.
        m.d.comb += [

            # We'll only ever -write- data from our input stream...
            buffer_write_ports[0].data   .eq(in_stream.payload),
            buffer_write_ports[0].addr   .eq(write_fill_count),
            buffer_write_ports[1].data   .eq(in_stream.payload),
            buffer_write_ports[1].addr   .eq(write_fill_count),

            # ... and we'll only ever -send- data from the Read buffer.
            buffer_read.addr             .eq(send_position),
            out_stream.payload           .eq(buffer_read.data),

            # We're ready to receive data iff we have space in the buffer we're currently filling.
            in_stream.ready              .eq((write_fill_count != self._max_packet_size) & ~write_stream_ended),
            buffer_write.en              .eq(in_stream.valid & in_stream.ready)
        ]

        # Increment our fill count whenever we accept new data.
        with m.If(buffer_write.en):
            m.d.usb += write_fill_count.eq(write_fill_count + 1)

        # If the stream ends while we're adding data to the buffer, mark this as an ended stream.
        with m.If(in_stream.last & buffer_write.en):
            m.d.usb += write_stream_ended.eq(1)


        # Shortcut for when we need to deal with an in token.
        # Pulses high an interpacket delay after receiving an IN token.
        in_token_received = self.active & self.tokenizer.is_in & self.tokenizer.ready_for_response

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

            # WAIT_FOR_DATA -- We don't yet have a full packet to transmit, so  we'll capture data
            # to fill the our buffer. At full throughput, this state will never be reached after
            # the initial post-reset fill.
            with m.State("WAIT_FOR_DATA"):

                # We can't yet send data; so NAK any packet requests.
                m.d.comb += self.handshakes_out.nak.eq(in_token_received)

                # If we have valid data that will end our packet, we're no longer waiting for data.
                # We'll now wait for the host to request data from us.
                packet_complete = (write_fill_count + 1 == self._max_packet_size)
                will_end_packet = packet_complete | in_stream.last

                with m.If(in_stream.valid & will_end_packet):

                    # If we've just finished a packet, we now have data we can send!
                    with m.If(packet_complete | in_stream.last):
                        m.next = "WAIT_TO_SEND"
                        m.d.usb += [

                            # We're now ready to take the data we've captured and _transmit_ it.
                            # We'll swap our read and write buffers, and toggle our data PID.
                            self.buffer_toggle  .eq(~self.buffer_toggle),
                            self.data_pid[0]    .eq(~self.data_pid[0]),

                            # Mark our current stream as no longer having ended.
                            read_stream_ended  .eq(0)
                        ]


            # WAIT_TO_SEND -- we now have at least a buffer full of data to send; we'll
            # need to wait for an IN token to send it.
            with m.State("WAIT_TO_SEND"):
                m.d.usb += send_position .eq(0),

                # Once we get an IN token, move to sending a packet.
                with m.If(in_token_received):

                    # If we have a packet to send, send it.
                    with m.If(read_fill_count):
                        m.next = "SEND_PACKET"
                        m.d.usb += out_stream.first  .eq(1)

                    # Otherwise, we entered a transmit path without any data in the buffer.
                    with m.Else():
                        m.d.comb += [
                            # Send a ZLP...
                            out_stream.valid  .eq(1),
                            out_stream.last   .eq(1),
                        ]
                        # ... and clear the need to follow up with one, since we've just sent a short packet.
                        m.d.usb += read_stream_ended.eq(0)
                        m.next = "WAIT_FOR_ACK"


            with m.State("SEND_PACKET"):
                last_packet = (send_position + 1 == read_fill_count)

                m.d.comb += [
                    # We're always going to be sending valid data, since data is always
                    # available from our memory.
                    out_stream.valid  .eq(1),

                    # Let our transmitter know when we've reached our last packet.
                    out_stream.last   .eq(last_packet)
                ]

                # Once our transmitter accepts our data...
                with m.If(out_stream.ready):

                    m.d.usb += [
                        # ... move to the next byte in our packet ...
                        send_position     .eq(send_position + 1),

                        # ... and mark our packet as no longer the first.
                        out_stream.first  .eq(0)
                    ]

                    # Move our memory pointer to its next position.
                    m.d.comb += buffer_read.addr  .eq(send_position + 1),

                    # If we've just sent our last packet, we're now ready to wait for a
                    # response from our host.
                    with m.If(last_packet):
                        m.next = 'WAIT_FOR_ACK'


            # WAIT_FOR_ACK -- We've just sent a packet; but don't know if the host has
            # received it correctly. We'll wait to see if the host ACKs.
            with m.State("WAIT_FOR_ACK"):

                # If the host does ACK...
                with m.If(self.handshakes_in.ack):
                    # ... clear the data we've sent from our buffer.
                    m.d.usb += read_fill_count.eq(0)

                    # Figure out if we'll need to follow up with a ZLP. If we have ZLP generation enabled,
                    # we'll make sure we end on a short packet. If this is max-packet-size packet _and_ our
                    # transfer ended with this packet; we'll need to inject a ZLP.
                    follow_up_with_zlp = \
                        self.generate_zlps & (read_fill_count == self._max_packet_size) & read_stream_ended

                    # If we're following up with a ZLP, move back to our "wait to send" state.
                    # Since we've now cleared our fill count; this next go-around will emit a ZLP.
                    with m.If(follow_up_with_zlp):
                        m.d.usb += self.data_pid[0].eq(~self.data_pid[0]),
                        m.next = "WAIT_TO_SEND"

                    # Otherwise, there's a possibility we already have a packet-worth of data waiting
                    # for us in our "write buffer", which we've been filling in the background.
                    # If this is the case, we'll flip which buffer we're working with, toggle our data pid,
                    # and then ready ourselves for transmit.
                    packet_completing = in_stream.valid & ((write_fill_count + 1 == self._max_packet_size) | in_stream.last)
                    with m.Elif(~in_stream.ready | packet_completing):
                        m.next = "WAIT_TO_SEND"
                        m.d.usb += [
                            self.buffer_toggle .eq(~self.buffer_toggle),
                            self.data_pid[0]   .eq(~self.data_pid[0]),
                            read_stream_ended  .eq(0)
                        ]

                    # If neither of the above conditions are true; we now don't have enough data to send.
                    # We'll wait for enough data to transmit.
                    with m.Else():
                        m.next = "WAIT_FOR_DATA"


                # If the host starts a new packet without ACK'ing, we'll need to retransmit.
                # We'll move back to our "wait for token" state without clearing our buffer.
                with m.If(self.tokenizer.new_token):
                    m.next = 'WAIT_TO_SEND'

        return m
Ejemplo n.º 16
0
    def elaborate(self, platform):
        m = Module()

        #
        # Clock/Data recovery.
        #
        clock_data_recovery = RxClockDataRecovery(self.i_usbp, self.i_usbn)
        m.submodules.clock_data_recovery = clock_data_recovery
        m.d.comb += self.o_bit_strobe.eq(clock_data_recovery.line_state_valid)

        #
        # NRZI decoding
        #
        m.submodules.nrzi = nrzi = RxNRZIDecoder()
        m.d.comb += [
            nrzi.i_valid.eq(self.o_bit_strobe),
            nrzi.i_dj.eq(clock_data_recovery.line_state_dj),
            nrzi.i_dk.eq(clock_data_recovery.line_state_dk),
            nrzi.i_se0.eq(clock_data_recovery.line_state_se0),
        ]

        #
        # Packet boundary detection.
        #
        m.submodules.detect = detect = ResetInserter(self.reset)(
            RxPacketDetect())
        m.d.comb += [
            detect.i_valid.eq(nrzi.o_valid),
            detect.i_se0.eq(nrzi.o_se0),
            detect.i_data.eq(nrzi.o_data),
        ]

        #
        # Bitstuff remover.
        #
        m.submodules.bitstuff = bitstuff = \
            ResetInserter(~detect.o_pkt_active)(RxBitstuffRemover())
        m.d.comb += [
            bitstuff.i_valid.eq(nrzi.o_valid),
            bitstuff.i_data.eq(nrzi.o_data),
            self.o_receive_error.eq(bitstuff.o_error)
        ]

        #
        # 1bit->8bit (1byte) gearing
        #
        m.submodules.shifter = shifter = RxShifter(width=8)
        m.d.comb += [
            shifter.reset.eq(detect.o_pkt_end),
            shifter.i_data.eq(bitstuff.o_data),
            shifter.i_valid.eq(~bitstuff.o_stall
                               & Past(detect.o_pkt_active, domain="usb_io")),
        ]

        #
        # Clock domain crossing.
        #
        flag_start = Signal()
        flag_end = Signal()
        flag_valid = Signal()
        m.submodules.payload_fifo = payload_fifo = AsyncFIFOBuffered(
            width=8, depth=4, r_domain="usb", w_domain="usb_io")
        m.d.comb += [
            payload_fifo.w_data.eq(shifter.o_data[::-1]),
            payload_fifo.w_en.eq(shifter.o_put),
            self.o_data_payload.eq(payload_fifo.r_data),
            self.o_data_strobe.eq(payload_fifo.r_rdy),
            payload_fifo.r_en.eq(1)
        ]

        m.submodules.flags_fifo = flags_fifo = AsyncFIFOBuffered(
            width=2, depth=4, r_domain="usb", w_domain="usb_io")
        m.d.comb += [
            flags_fifo.w_data[1].eq(detect.o_pkt_start),
            flags_fifo.w_data[0].eq(detect.o_pkt_end),
            flags_fifo.w_en.eq(detect.o_pkt_start | detect.o_pkt_end),
            flag_start.eq(flags_fifo.r_data[1]),
            flag_end.eq(flags_fifo.r_data[0]),
            flag_valid.eq(flags_fifo.r_rdy),
            flags_fifo.r_en.eq(1),
        ]

        # Packet flag signals (in 12MHz domain)
        m.d.comb += [
            self.o_pkt_start.eq(flag_start & flag_valid),
            self.o_pkt_end.eq(flag_end & flag_valid),
        ]

        with m.If(self.o_pkt_start):
            m.d.usb += self.o_pkt_in_progress.eq(1)
        with m.Elif(self.o_pkt_end):
            m.d.usb += self.o_pkt_in_progress.eq(0)

        return m
Ejemplo n.º 17
0
    def elaborate(self, platform) -> Module:
        m = Module()
        sync = m.d.sync
        adat = m.d.adat
        comb = m.d.comb

        samples_write_port = self.mem.write_port()
        samples_read_port  = self.mem.read_port(domain='comb')
        m.submodules += [samples_write_port, samples_read_port]

        # the highest bit in the FIFO marks a frame border
        frame_border_flag = 24
        m.submodules.transmit_fifo = transmit_fifo = AsyncFIFO(width=25, depth=self._fifo_depth, w_domain="sync", r_domain="adat")

        # needed for output processing
        m.submodules.nrzi_encoder = nrzi_encoder = NRZIEncoder()

        transmitted_frame      = Signal(30)
        transmit_counter       = Signal(5)

        comb += [
            self.ready_out       .eq(transmit_fifo.w_rdy),
            self.fifo_level_out  .eq(transmit_fifo.w_level),
            self.adat_out        .eq(nrzi_encoder.nrzi_out),
            nrzi_encoder.data_in .eq(transmitted_frame.bit_select(transmit_counter, 1)),
            self.underflow_out   .eq(0)
        ]

        #
        # Fill the transmit FIFO in the sync domain
        #
        channel_counter = Signal(3)

        # make sure, en is only asserted when explicitly strobed
        comb += samples_write_port.en.eq(0)

        write_frame_border = [
            transmit_fifo.w_data .eq((1 << frame_border_flag) | self.user_data_in),
            transmit_fifo.w_en   .eq(1)
        ]

        with m.FSM():
            with m.State("DATA"):
                with m.If(self.ready_out):
                    with m.If(self.valid_in):
                        comb += [
                            samples_write_port.data.eq(self.sample_in),
                            samples_write_port.addr.eq(self.addr_in),
                            samples_write_port.en.eq(1)
                        ]

                        with m.If(self.last_in):
                            sync += channel_counter.eq(0)
                            comb += write_frame_border
                            m.next = "COMMIT"

                    # underflow: repeat last frame
                    with m.Elif(transmit_fifo.w_level == 0):
                        sync += channel_counter.eq(0)
                        comb += self.underflow_out.eq(1)
                        comb += write_frame_border
                        m.next = "COMMIT"

            with m.State("COMMIT"):
                with m.If(transmit_fifo.w_rdy):
                    comb += [
                        self.ready_out.eq(0),
                        samples_read_port.addr .eq(channel_counter),
                        transmit_fifo.w_data   .eq(samples_read_port.data),
                        transmit_fifo.w_en     .eq(1)
                    ]
                    sync += channel_counter.eq(channel_counter + 1)

                    with m.If(channel_counter == 7):
                        m.next = "DATA"

        #
        # Read the FIFO and send data in the adat domain
        #
        # 4b/5b coding: Every 24 bit channel has 6 nibbles.
        # 1 bit before the sync pad and one bit before the user data nibble
        filler_bits = [Const(1, 1) for _ in range(7)]

        adat += transmit_counter.eq(transmit_counter - 1)
        comb += transmit_fifo.r_en.eq(0)

        with m.If(transmit_counter == 0):
            with m.If(transmit_fifo.r_rdy):
                comb += transmit_fifo.r_en.eq(1)

                with m.If(transmit_fifo.r_data[frame_border_flag] == 0):
                    adat += [
                        transmit_counter.eq(29),
                        # generate the adat data for one channel 0b1dddd1dddd1dddd1dddd1dddd1dddd where d is the PCM audio data
                        transmitted_frame.eq(Cat(zip(list(self.chunks(transmit_fifo.r_data[:25], 4)), filler_bits)))
                    ]
                with m.Else():
                    adat += [
                        transmit_counter.eq(15),
                        # generate the adat sync_pad along with the user_bits 0b100000000001uuuu where u is user_data
                        transmitted_frame.eq((1 << 15) | (1 << 4) | transmit_fifo.r_data[:5])
                    ]

            with m.Else():
                # this should not happen: panic / stop transmitting.
                adat += [
                    transmitted_frame.eq(0x00),
                    transmit_counter.eq(4)
                ]

        return m
Ejemplo n.º 18
0
    def elaborate(self, platform):
        m = Module()

        #
        # General state signals.
        #

        # Our line state is always taken directly from D- and D+.
        m.d.comb += self.line_state.eq(Cat(self._io.d_n.i, self._io.d_p.i))

        # If we have a ``vbus_valid`` indication, use it to drive our ``vbus_valid``
        # signal. Otherwise, we'll pretend ``vbus_valid`` is always true, for compatibility.
        if hasattr(self._io, 'vbus_valid'):
            m.d.comb += [
                self.vbus_valid.eq(self._io.vbus_valid),
                self.session_end.eq(~self._io.vbus_valid)
            ]
        else:
            m.d.comb += [self.vbus_valid.eq(1), self.session_end.eq(0)]

        #
        # General control signals.
        #

        # If we have a pullup signal, drive it based on ``term_select``.
        if hasattr(self._io, 'pullup'):
            m.d.comb += self._io.pullup.eq(self.term_select)

        # If we have a pulldown signal, drive it based on our pulldown controls.
        if hasattr(self._io, 'pulldown'):
            m.d.comb += self._io.pullup.eq(self.dm_pulldown | self.dp_pulldown)

        #
        # Transmitter
        #
        in_normal_mode = (self.op_mode == self.OP_MODE_NORMAL)
        in_non_encoding_mode = (self.op_mode == self.OP_MODE_NO_ENCODING)

        m.submodules.transmitter = transmitter = TxPipeline()

        # When we're in normal mode, we'll drive the USB bus with our standard USB transmitter data.
        with m.If(in_normal_mode):
            m.d.comb += [

                # UTMI Transmit data.
                transmitter.i_data_payload.eq(self.tx_data),
                transmitter.i_oe.eq(self.tx_valid),
                self.tx_ready.eq(transmitter.o_data_strobe),

                # USB output.
                self._io.d_p.o.eq(transmitter.o_usbp),
                self._io.d_n.o.eq(transmitter.o_usbn),

                # USB tri-state control.
                self._io.d_p.oe.eq(transmitter.o_oe),
                self._io.d_n.oe.eq(transmitter.o_oe),
            ]

        # When we're in non-encoding mode ("disable bitstuff and NRZI"),
        # we'll output to D+ and D- directly when tx_valid is true.
        with m.Elif(in_non_encoding_mode):
            m.d.comb += [
                # USB output.
                self._io.d_p.o.eq(self.tx_data),
                self._io.d_n.o.eq(~self.tx_data),

                # USB tri-state control.
                self._io.d_p.oe.eq(self.tx_valid),
                self._io.d_n.oe.eq(self.tx_valid)
            ]

        # When we're in other modes (non-driving or invalid), we'll not output at all.
        # This block does nothing, as signals default to zero, but it makes the intention obvious.
        with m.Else():
            m.d.comb += [
                self._io.d_p.oe.eq(0),
                self._io.d_n.oe.eq(0),
            ]

        # Generate our USB clock strobe, which should pulse at 12MHz.
        counter = Signal(2)
        m.d.usb_io += counter.eq(counter + 1)
        m.d.comb += transmitter.i_bit_strobe.eq(counter == 0)

        #
        # Receiver
        #
        m.submodules.receiver = receiver = RxPipeline()
        m.d.comb += [

            # We'll listen for packets on D+ and D- _whenever we're not transmitting._.
            # (If we listen while we're transmitting, we'll hear our own packets.)
            receiver.i_usbp.eq(self._io.d_p & ~transmitter.o_oe),
            receiver.i_usbn.eq(self._io.d_n & ~transmitter.o_oe),
            self.rx_data.eq(receiver.o_data_payload),
            self.rx_valid.eq(receiver.o_data_strobe
                             & receiver.o_pkt_in_progress),
            self.rx_active.eq(receiver.o_pkt_in_progress),
            self.rx_error.eq(receiver.o_receive_error)
        ]
        m.d.usb += self.rx_complete.eq(receiver.o_pkt_end)

        return m
Ejemplo n.º 19
0
    def elaborate(self, platform):
        m = Module()
        state = Signal(3)

        def get_all_resources(name):
            resources = []
            for number in itertools.count():
                try:
                    resources.append(platform.request(name, number))
                except ResourceError:
                    break
            return resources

        if platform and self.top:
            board_spi = platform.request("debug_spi")
            spi2 = synchronize(m, board_spi)

            leds = [res.o for res in get_all_resources("led")]
            bldc = platform.request("bldc")
            m.d.comb += self.spi.connect(spi2)

            m.d.comb += [
                leds[0].eq(bldc.sensor0), leds[1].eq(bldc.sensor1),
                leds[2].eq(bldc.sensor2)
            ]
            # tested by trying out all possibilities
            m.d.sync += state.eq(Cat(bldc.sensor0, bldc.sensor1, bldc.sensor2))
        else:
            platform = self.platform
            bldc = platform.bldc

        target = 200000
        max_measurement = target * 10
        measurement = Signal(range(max_measurement))
        timer = Signal().like(measurement)
        statefilter = Signal(3)
        stateold = Signal(3)
        max_delay = 1000
        delay = Signal(range(max_delay))

        # Statefilter
        with m.If((state >= 1) & (state <= 6)):
            m.d.sync += statefilter.eq(state)

        m.d.sync += stateold.eq(statefilter)

        # PID controller
        step = max_delay // 100
        with m.If((measurement > target) & (delay >= step)):
            m.d.sync += delay.eq(delay - step)
        with m.Elif((measurement < target) & (delay < (max_delay - step))):
            m.d.sync += delay.eq(delay + step)
        with m.Else():
            m.d.sync += delay.eq(0)

        # Measure Cycle
        with m.If(timer >= max_measurement - 1):
            m.d.sync += [timer.eq(0), measurement.eq(timer)]
        with m.Elif((statefilter == 1) & (stateold != 1)):
            m.d.sync += [measurement.eq(timer), timer.eq(0)]
        with m.Else():
            m.d.sync += timer.eq(timer + 1)

        spi = self.spi
        interf = SPICommandInterface(command_size=1 * 8, word_size=4 * 8)
        m.d.comb += interf.spi.connect(spi)
        m.submodules.interf = interf
        m.d.sync += interf.word_to_send.eq(measurement)

        off = Signal()
        duty = Signal(range(max_delay))

        # Duty timer
        with m.If(duty < max_delay):
            m.d.sync += duty.eq(0)
        with m.Else():
            m.d.sync += duty.eq(duty + 1)

        # Motor On / Off
        with m.If(duty < delay):
            m.d.sync += off.eq(1)
        with m.Else():
            m.d.sync += off.eq(0)

        # https://www.mathworks.com/help/mcb/ref/sixstepcommutation.html
        with m.If(off):
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(0)
            ]
        with m.Elif(statefilter == 1):  # V --> W, 001
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(1),
                bldc.wL.eq(1),
                bldc.wH.eq(0)
            ]
        with m.Elif(statefilter == 3):  # V --> U, 011
            m.d.comb += [
                bldc.uL.eq(1),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(1),
                bldc.wL.eq(0),
                bldc.wH.eq(0)
            ]
        with m.Elif(statefilter == 2):  # W --> U, 010
            m.d.comb += [
                bldc.uL.eq(1),
                bldc.uH.eq(0),
                bldc.vL.eq(0),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(1)
            ]
        with m.Elif(statefilter == 6):  # W --> V, 110
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(0),
                bldc.vL.eq(1),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(1)
            ]
        with m.Elif(statefilter == 4):  # U --> V, 100
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(1),
                bldc.vL.eq(1),
                bldc.vH.eq(0),
                bldc.wL.eq(0),
                bldc.wH.eq(0)
            ]
        with m.Elif(statefilter == 5):  # U --> W, 101
            m.d.comb += [
                bldc.uL.eq(0),
                bldc.uH.eq(1),
                bldc.vL.eq(0),
                bldc.vH.eq(0),
                bldc.wL.eq(1),
                bldc.wH.eq(0)
            ]
        # with m.Else():         # disabled
        #     m.d.comb += [bldc.uL.eq(0),
        #                  bldc.uH.eq(0),
        #                  bldc.vL.eq(0),
        #                  bldc.vH.eq(0),
        #                  bldc.wL.eq(0),
        #                  bldc.wH.eq(0)]
        return m
Ejemplo n.º 20
0
    def elaborate(self, platform):
        m = Module()

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

        registers = JTAGRegisterInterface(default_read_value=0xDEADBEEF)
        m.submodules.registers = registers

        # Simple applet ID register.
        registers.add_read_only_register(REGISTER_ID, read=0x54455354)

        # LED test register.
        led_reg = registers.add_register(REGISTER_LEDS,
                                         size=6,
                                         name="leds",
                                         reset=0b111111)
        led_out = Cat(
            [platform.request("led", i, dir="o") for i in range(0, 6)])
        m.d.comb += led_out.eq(led_reg)

        #
        # Target power test register.
        # Note: these values assume you've populated the correct AP22814 for
        #       your revision (AP22814As for rev0.2+, and AP22814Bs for rev0.1).
        #     bits [1:0]: 0 = power off
        #                 1 = provide A-port VBUS
        #                 2 = pass through target VBUS
        #
        power_test_reg = Signal(3)
        power_test_write_strobe = Signal()
        power_test_write_value = Signal(2)
        registers.add_sfr(REGISTER_TARGET_POWER,
                          read=power_test_reg,
                          write_strobe=power_test_write_strobe,
                          write_signal=power_test_write_value)

        # Store the values for our enable bits.
        with m.If(power_test_write_strobe):
            m.d.sync += power_test_reg[0:2].eq(power_test_write_value)

        # Decode the enable bits and control the two power supplies.
        power_a_port = platform.request("power_a_port")
        power_passthrough = platform.request("pass_through_vbus")
        with m.If(power_test_reg[0:2] == 1):
            m.d.comb += [power_a_port.eq(1), power_passthrough.eq(0)]
        with m.Elif(power_test_reg[0:2] == 2):
            m.d.comb += [power_a_port.eq(0), power_passthrough.eq(1)]
        with m.Else():
            m.d.comb += [power_a_port.eq(0), power_passthrough.eq(0)]

        #
        # User IO GPIO registers.
        #

        # Data direction register.
        user_io_dir = registers.add_register(REGISTER_USER_IO_DIR, size=2)

        # Pin (input) state register.
        user_io_in = Signal(2)
        registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in)

        # Output value register.
        user_io_out = registers.add_register(REGISTER_USER_IO_OUT, size=2)

        # Grab and connect each of our user-I/O ports our GPIO registers.
        for i in range(2):
            pin = platform.request("user_io", i)
            m.d.comb += [
                pin.oe.eq(user_io_dir[i]), user_io_in[i].eq(pin.i),
                pin.o.eq(user_io_out[i])
            ]

        #
        # ULPI PHY windows
        #
        self.add_ulpi_registers(m,
                                platform,
                                ulpi_bus="target_phy",
                                register_base=REGISTER_TARGET_ADDR)
        self.add_ulpi_registers(m,
                                platform,
                                ulpi_bus="host_phy",
                                register_base=REGISTER_HOST_ADDR)
        self.add_ulpi_registers(m,
                                platform,
                                ulpi_bus="sideband_phy",
                                register_base=REGISTER_SIDEBAND_ADDR)

        #
        # HyperRAM test connections.
        #
        ram_bus = platform.request('ram')
        psram = HyperRAMInterface(bus=ram_bus, **platform.ram_timings)
        m.submodules += psram

        psram_address_changed = Signal()
        psram_address = registers.add_register(
            REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed)

        registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data)

        # Hook up our PSRAM.
        m.d.comb += [
            ram_bus.reset.eq(0),
            psram.single_page.eq(0),
            psram.perform_write.eq(0),
            psram.register_space.eq(1),
            psram.final_word.eq(1),
            psram.start_transfer.eq(psram_address_changed),
            psram.address.eq(psram_address),
        ]

        return m
Ejemplo n.º 21
0
    def elaborate(self, platform):
        m = Module()

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

        targeting_ep_num = (
            interface.tokenizer.endpoint == self._endpoint_number)
        targeting_us = targeting_ep_num & interface.tokenizer.is_in
        data_requested = targeting_us & interface.tokenizer.ready_for_response

        # Track our state in our transmission.
        bytes_left_in_frame = Signal.like(self.bytes_in_frame)
        bytes_left_in_packet = Signal(range(0, self._max_packet_size + 1),
                                      reset=self._max_packet_size - 1)
        next_data_pid = Signal(2)

        # Reset our state at the start of each frame.
        with m.If(new_frame):

            m.d.usb += [
                # Latch in how many bytes we'll be transmitting this frame.
                bytes_left_in_frame.eq(self.bytes_in_frame),

                # And start with a full packet to transmit.
                bytes_left_in_packet.eq(self._max_packet_size)
            ]

            # If it'll take more than two packets to send our data, start off with DATA2.
            # We'll follow with DATA1 and DATA0.
            with m.If(self.bytes_in_frame > (2 * self._max_packet_size)):
                m.d.usb += next_data_pid.eq(2)

            # Otherwise, if we need two, start with DATA1.
            with m.Elif(self.bytes_in_frame > self._max_packet_size):
                m.d.usb += next_data_pid.eq(1)

            # Otherwise, we'll start (and end) with DATA0.
            with m.Else():
                m.d.usb += next_data_pid.eq(0)

        m.d.comb += [
            # Always pass our ``value`` directly through to our transmitter.
            # We'll provide ``address``/``next_address`` to our user code to help
            # orchestrate this timing.
            out_stream.payload.eq(self.value),

            # Provide our data pid through to to the transmitter.
            interface.tx_pid_toggle.eq(next_data_pid)
        ]

        #
        # Core sequencing FSM.
        #
        with m.FSM(domain="usb"):

            # IDLE -- the host hasn't yet requested data from our endpoint.
            with m.State("IDLE"):
                m.d.usb += [
                    # Remain targeting the first byte in our frame.
                    self.address.eq(0),
                    out_stream.first.eq(0)
                ]

                m.d.comb += self.next_address.eq(0)

                # Once the host requests a packet from us...
                with m.If(data_requested):

                    # If we have data to send, send it.
                    with m.If(bytes_left_in_frame):
                        m.d.usb += out_stream.first.eq(1)
                        m.next = "SEND_DATA"

                    # Otherwise, we'll send a ZLP.
                    with m.Else():
                        m.next = "SEND_ZLP"

            # SEND_DATA -- our primary data-transmission state; handles packet transmission
            with m.State("SEND_DATA"):
                last_byte_in_packet = (bytes_left_in_packet <= 1)
                last_byte_in_frame = (bytes_left_in_frame <= 1)
                byte_terminates_send = last_byte_in_packet | last_byte_in_frame

                m.d.comb += [
                    # Our data is always valid in this state...
                    out_stream.valid.eq(1),

                    # ... and we're terminating our packet if we're on the last byte of it.
                    out_stream.last.eq(byte_terminates_send),
                ]

                # ``address`` should always move to the value presented in
                # ``next_address`` on each clock edge.
                m.d.usb += self.address.eq(self.next_address)

                # By default, don't advance.
                m.d.comb += self.next_address.eq(self.address)

                # We'll advance each time our data is accepted.
                with m.If(out_stream.ready):
                    m.d.usb += out_stream.first.eq(0)

                    # Mark the relevant byte as sent...
                    m.d.usb += [
                        bytes_left_in_frame.eq(bytes_left_in_frame - 1),
                        bytes_left_in_packet.eq(bytes_left_in_packet - 1),
                    ]

                    # ... and advance to the next address.
                    m.d.comb += self.next_address.eq(self.address + 1)

                    # If we've just completed transmitting a packet, or we've
                    # just transmitted a full frame, end our transmission.
                    with m.If(byte_terminates_send):
                        m.d.usb += [
                            # Move to the next DATA pid, which is always one DATA PID less.
                            # [USB2.0: 5.9.2]. We'll reset this back to its maximum value when
                            # the next frame starts.
                            next_data_pid.eq(next_data_pid - 1),

                            # Mark our next packet as being a full one.
                            bytes_left_in_packet.eq(self._max_packet_size)
                        ]
                        m.next = "IDLE"

            # SEND_ZLP -- sends a zero-length packet, and then return to idle.
            with m.State("SEND_ZLP"):
                # We'll request a ZLP by strobing LAST and VALID without strobing FIRST.
                m.d.comb += [
                    out_stream.valid.eq(1),
                    out_stream.last.eq(1),
                ]
                m.next = "IDLE"

        return m
Ejemplo n.º 22
0
    def elaborate(self, platform) -> Module:
        """build the module"""
        m = Module()
        sync = m.d.sync
        comb = m.d.comb

        nrzidecoder = NRZIDecoder(self.clk_freq)
        m.submodules.nrzi_decoder = nrzidecoder

        framedata_shifter = InputShiftRegister(24)
        m.submodules.framedata_shifter = framedata_shifter

        output_pulser = EdgeToPulse()
        m.submodules.output_pulser = output_pulser

        active_channel = Signal(3)
        # counts the number of bits output
        bit_counter      = Signal(8)
        # counts the bit position inside a nibble
        nibble_counter   = Signal(3)
        # counts, how many 0 bits it got in a row
        sync_bit_counter = Signal(4)

        comb += [
            nrzidecoder.nrzi_in.eq(self.adat_in),
            self.synced_out.eq(nrzidecoder.running),
            self.recovered_clock_out.eq(nrzidecoder.recovered_clock_out),
        ]

        with m.FSM():
            # wait for SYNC
            with m.State("WAIT_SYNC"):
                # reset invalid frame bit to be able to start again
                with m.If(nrzidecoder.invalid_frame_in):
                    sync += nrzidecoder.invalid_frame_in.eq(0)

                with m.If(nrzidecoder.running):
                    sync += [
                        bit_counter.eq(0),
                        nibble_counter.eq(0),
                        active_channel.eq(0),
                        output_pulser.edge_in.eq(0)
                    ]

                    with m.If(nrzidecoder.data_out_en):
                        m.d.sync += sync_bit_counter.eq(Mux(nrzidecoder.data_out, 0, sync_bit_counter + 1))
                        with m.If(sync_bit_counter == 9):
                            m.d.sync += sync_bit_counter.eq(0)
                            m.next = "READ_FRAME"

            with m.State("READ_FRAME"):
                # at which bit of bit_counter to output sample data at
                output_at = Signal(8)

                # user bits have been read
                with m.If(bit_counter == 5):
                    sync += [
                        # output user bits
                        self.user_data_out.eq(framedata_shifter.value_out[0:4]),
                        # at bit 35 the first channel has been read
                        output_at.eq(35)
                    ]

                # when each channel has been read, output the channel's sample
                with m.If((bit_counter > 5) & (bit_counter == output_at)):
                    sync += [
                        self.output_enable.eq(1),
                        self.addr_out.eq(active_channel),
                        self.sample_out.eq(framedata_shifter.value_out),
                        output_at.eq(output_at + 30),
                        active_channel.eq(active_channel + 1)
                    ]
                with m.Else():
                    sync += self.output_enable.eq(0)

                # we work and count only when we get
                # a new bit fron the NRZI decoder
                with m.If(nrzidecoder.data_out_en):
                    comb += [
                        framedata_shifter.bit_in.eq(nrzidecoder.data_out),
                        # skip sync bit, which is first
                        framedata_shifter.enable_in.eq(~(nibble_counter == 0))
                    ]
                    sync += [
                        nibble_counter.eq(nibble_counter + 1),
                        bit_counter.eq(bit_counter + 1),
                    ]

                    # check 4b/5b sync bit
                    with m.If((nibble_counter == 0) & ~nrzidecoder.data_out):
                        sync += nrzidecoder.invalid_frame_in.eq(1)
                        m.next = "WAIT_SYNC"
                    with m.Else():
                        sync += nrzidecoder.invalid_frame_in.eq(0)

                    with m.If(nibble_counter >= 4):
                        sync += nibble_counter.eq(0)

                    # 239 channel bits and 5 user bits (including sync bits)
                    with m.If(bit_counter >= (239 + 5)):
                        sync += [
                            bit_counter.eq(0),
                            output_pulser.edge_in.eq(1)
                        ]
                        m.next = "READ_SYNC"

                with m.Else():
                    comb += framedata_shifter.enable_in.eq(0)

                with m.If(~nrzidecoder.running):
                    m.next = "WAIT_SYNC"

            # read the sync bits
            with m.State("READ_SYNC"):
                sync += [
                    self.output_enable.eq(output_pulser.pulse_out),
                    self.addr_out.eq(active_channel),
                    self.sample_out.eq(framedata_shifter.value_out),
                ]

                with m.If(nrzidecoder.data_out_en):
                    sync += [
                        nibble_counter.eq(0),
                        bit_counter.eq(bit_counter + 1),
                    ]

                    with m.If(bit_counter == 9):
                        comb += [
                            framedata_shifter.enable_in.eq(0),
                            framedata_shifter.clear_in.eq(1),
                        ]

                    #check last sync bit before sync trough
                    with m.If((bit_counter == 0) & ~nrzidecoder.data_out):
                        sync += nrzidecoder.invalid_frame_in.eq(1)
                        m.next = "WAIT_SYNC"
                    #check all the null bits in the sync trough
                    with m.Elif((bit_counter > 0) & nrzidecoder.data_out):
                        sync += nrzidecoder.invalid_frame_in.eq(1)
                        m.next = "WAIT_SYNC"
                    with m.Elif((bit_counter == 10) & ~nrzidecoder.data_out):
                        sync += [
                            bit_counter.eq(0),
                            nibble_counter.eq(0),
                            active_channel.eq(0),
                            output_pulser.edge_in.eq(0),
                            nrzidecoder.invalid_frame_in.eq(0)
                        ]
                        m.next = "READ_FRAME"
                    with m.Else():
                        sync += nrzidecoder.invalid_frame_in.eq(0)

                with m.If(~nrzidecoder.running):
                    m.next = "WAIT_SYNC"

        return m
Ejemplo n.º 23
0
    def elaborate(self, platform):
        m = Module()
        dct = self.dct

        # Pulse generator for prism motor
        pwmcnt = Signal(range(dct['POLYPERIOD']))
        # photodiode_triggered
        photodiodecnt = Signal(range(dct['TICKSINFACET'] * 2))
        triggered = Signal()
        with m.If(photodiodecnt < (dct['TICKSINFACET'] * 2 - 1)):
            with m.If(~self.photodiode):
                m.d.sync += triggered.eq(1)
            m.d.sync += photodiodecnt.eq(photodiodecnt + 1)
        with m.Else():
            m.d.sync += [
                self.photodiode_t.eq(triggered),
                photodiodecnt.eq(0),
                triggered.eq(0)
            ]

        # step generator, i.e. slowest speed is 1/(2^4-1)
        stephalfperiod = Signal(dct['BITSINSCANLINE'].bit_length() + 4)
        stepcnt = Signal.like(stephalfperiod)

        # pwm is always created but can be deactivated
        with m.If(pwmcnt == 0):
            m.d.sync += [
                self.pwm.eq(~self.pwm),
                pwmcnt.eq(dct['POLYPERIOD'] - 1)
            ]
        with m.Else():
            m.d.sync += pwmcnt.eq(pwmcnt - 1)

        # Laser FSM
        # stable thresh is changed, larger at start and then lowered
        stablethresh = Signal(range(dct['STABLETICKS']))
        facetcnt = Signal(range(dct['FACETS']))
        lasercnt = Signal(range(dct['LASERTICKS']))
        scanbit = Signal(range(dct['BITSINSCANLINE'] + 1))
        tickcounter = Signal(range(max(dct['SPINUPTICKS'],
                                       dct['STABLETICKS'])))
        scanlinenumber = Signal(range(255))
        photodiode = self.photodiode
        read_data = self.read_data
        write_data_2 = self.write_data_2
        write_new = Signal.like(write_data_2)
        read_old = Signal.like(read_data)
        readbit = Signal(range(MEMWIDTH))
        photodiode_d = Signal()
        lasers = self.lasers
        if self.platform.name == 'Test':
            self.stephalfperiod = stephalfperiod
            self.tickcounter = tickcounter
            self.scanbit = scanbit
            self.lasercnt = lasercnt
            self.facetcnt = facetcnt

        # Exposure start detector
        expose_start_d = Signal()

        m.d.sync += expose_start_d.eq(self.expose_start)
        with m.If((expose_start_d == 0) & self.expose_start):
            m.d.sync += [self.process_lines.eq(1), self.expose_finished.eq(0)]

        with m.FSM(reset='RESET') as laserfsm:
            with m.State('RESET'):
                m.d.sync += self.error.eq(0)
                m.next = 'STOP'
            with m.State('STOP'):
                m.d.sync += [
                    stablethresh.eq(dct['STABLETICKS'] - 1),
                    tickcounter.eq(0),
                    self.synchronized.eq(0),
                    self.enable_prism.eq(0),
                    readbit.eq(0),
                    facetcnt.eq(0),
                    scanbit.eq(0),
                    lasercnt.eq(0),
                    lasers.eq(0)
                ]
                with m.If(self.synchronize & (~self.error)):
                    # laser is off, photodiode cannot be triggered
                    with m.If(self.photodiode == 0):
                        m.d.sync += self.error.eq(1)
                        m.next = 'STOP'
                    with m.Else():
                        m.d.sync += [self.error.eq(0), self.enable_prism.eq(1)]
                        m.next = 'SPINUP'
            with m.State('SPINUP'):
                with m.If(tickcounter > dct['SPINUPTICKS'] - 1):
                    # turn on laser
                    m.d.sync += [
                        self.lasers.eq(int('1' * 2, 2)),
                        tickcounter.eq(0)
                    ]
                    m.next = 'WAIT_STABLE'
                with m.Else():
                    m.d.sync += tickcounter.eq(tickcounter + 1)
            with m.State('WAIT_STABLE'):
                m.d.sync += photodiode_d.eq(photodiode)
                with m.If(tickcounter >= stablethresh):
                    m.d.sync += self.error.eq(1)
                    m.next = 'STOP'
                with m.Elif(~photodiode & ~photodiode_d):
                    m.d.sync += [tickcounter.eq(0), lasers.eq(0)]
                    with m.If(
                        (tickcounter >
                         (dct['TICKSINFACET'] - 1) - dct['JITTERTICKS'])):
                        m.d.sync += [
                            self.synchronized.eq(1),
                            tickcounter.eq(0)
                        ]
                        with m.If(facetcnt == dct['FACETS'] - 1):
                            m.d.sync += facetcnt.eq(0)
                        with m.Else():
                            m.d.sync += facetcnt.eq(facetcnt + 1)
                        with m.If(dct['SINGLE_FACET'] & (facetcnt > 0)):
                            m.next = 'WAIT_END'
                        with m.Elif(self.empty | ~self.process_lines):
                            m.next = 'WAIT_END'
                        with m.Else():
                            # TODO: 10 is too high, should be lower
                            thresh = min(round(10.1 * dct['TICKSINFACET']),
                                         dct['STABLETICKS'])
                            m.d.sync += [
                                stablethresh.eq(thresh),
                                self.read_en.eq(1)
                            ]
                            m.next = 'READ_INSTRUCTION'
                    with m.Else():
                        m.d.sync += self.synchronized.eq(0)
                        m.next = 'WAIT_END'
                with m.Else():
                    m.d.sync += tickcounter.eq(tickcounter + 1)
            with m.State('READ_INSTRUCTION'):
                m.d.sync += [
                    self.read_en.eq(0),
                    tickcounter.eq(tickcounter + 1)
                ]
                with m.If(read_data[0:8] == INSTRUCTIONS.SCANLINE):
                    with m.If(scanlinenumber < 255):
                        m.d.sync += scanlinenumber.eq(scanlinenumber + 1)
                    with m.Else():
                        m.d.sync += scanlinenumber.eq(0)
                    m.d.sync += [
                        write_data_2.eq(scanlinenumber),
                        self.dir.eq(read_data[8]),
                        stephalfperiod.eq(read_data[9:])
                    ]
                    m.next = 'WAIT_FOR_DATA_RUN'
                with m.Elif(read_data == INSTRUCTIONS.LASTSCANLINE):
                    m.d.sync += [
                        self.expose_finished.eq(1),
                        self.read_commit.eq(1),
                        self.process_lines.eq(0)
                    ]
                    m.next = 'WAIT_END'
                with m.Else():
                    m.d.sync += self.error.eq(1)
                    m.next = 'READ_INSTRUCTION'
            with m.State('WAIT_FOR_DATA_RUN'):
                m.d.sync += [
                    tickcounter.eq(tickcounter + 1),
                    readbit.eq(0),
                    scanbit.eq(0),
                    lasercnt.eq(0)
                ]
                tickcnt_thresh = int(dct['START%'] * dct['TICKSINFACET'])
                assert tickcnt_thresh > 0
                with m.If(tickcounter >= tickcnt_thresh):
                    m.d.sync += [self.read_en.eq(1), self.write_en_2.eq(1)]
                    m.next = 'DATA_RUN'
            with m.State('DATA_RUN'):
                m.d.sync += tickcounter.eq(tickcounter + 1)
                # NOTE:
                #      readbit is your current position in memory
                #      scanbit current byte position in scanline
                #      lasercnt used to pulse laser at certain freq
                with m.If(lasercnt == 0):
                    with m.If(stepcnt >= stephalfperiod):
                        m.d.sync += [self.step.eq(~self.step), stepcnt.eq(0)]
                    with m.Else():
                        m.d.sync += stepcnt.eq(stepcnt + 1)
                    with m.If(scanbit >= dct['BITSINSCANLINE']):
                        m.d.sync += [
                            self.write_commit_2.eq(1),
                            self.lasers.eq(0)
                        ]
                        with m.If(dct['SINGLE_LINE'] & self.empty):
                            m.d.sync += self.read_discard.eq(1)
                        with m.Else():
                            m.d.sync += self.read_commit.eq(1)
                        m.next = 'WAIT_END'
                    with m.Else():
                        m.d.sync += [
                            lasercnt.eq(dct['LASERTICKS'] - 1),
                            scanbit.eq(scanbit + 1)
                        ]
                        m.d.sync += write_new[0].eq(self.photodiode_2)
                        with m.If(readbit == 0):
                            m.d.sync += [
                                self.lasers[0].eq(read_data[0]),
                                read_old.eq(read_data >> 1),
                                self.read_en.eq(0),
                                self.write_en_2.eq(0)
                            ]
                        with m.Elif(readbit == MEMWIDTH - 1):
                            m.d.sync += [
                                write_data_2.eq(write_new),
                                self.lasers[0].eq(read_old[0])
                            ]
                        with m.Else():
                            m.d.sync += self.lasers[0].eq(read_old[0])
                with m.Else():
                    m.d.sync += lasercnt.eq(lasercnt - 1)
                    # NOTE: read enable can only be high for 1 cycle
                    #       as a result this is done right before the "read"
                    with m.If(lasercnt == 1):
                        with m.If(readbit == 0):
                            m.d.sync += [readbit.eq(readbit + 1)]
                        # final read bit copy memory
                        # move to next address, i.e. byte, if end is reached
                        with m.Elif(readbit == MEMWIDTH - 1):
                            # If fifo is empty it will give errors later
                            # so it can be ignored here
                            # Only grab a new line if more than current
                            # is needed
                            # -1 as counting in python is different
                            with m.If(scanbit < (dct['BITSINSCANLINE'])):
                                m.d.sync += [
                                    self.read_en.eq(1),
                                    self.write_en_2.eq(1)
                                ]
                            m.d.sync += readbit.eq(0)
                        with m.Else():
                            m.d.sync += [
                                readbit.eq(readbit + 1),
                                read_old.eq(read_old >> 1)
                            ]
            with m.State('WAIT_END'):
                m.d.sync += [
                    tickcounter.eq(tickcounter + 1),
                    self.write_commit_2.eq(0)
                ]
                with m.If(dct['SINGLE_LINE'] & self.empty):
                    m.d.sync += self.read_discard.eq(0)
                with m.Else():
                    m.d.sync += self.read_commit.eq(0)
                # -1 as you count till range-1 in python
                # -2 as you need 1 tick to process
                with m.If(tickcounter >= round(dct['TICKSINFACET'] -
                                               dct['JITTERTICKS'] - 2)):
                    m.d.sync += lasers.eq(int('11', 2))
                    m.next = 'WAIT_STABLE'
                # if user disables synhcronization exit
                with m.If(~self.synchronize):
                    m.next = 'STOP'
        if self.platform.name == 'Test':
            self.laserfsm = laserfsm
        return m
Ejemplo n.º 24
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_stop.eq(1),
                    ]
                    m.next = 'STOPPING'

            with m.State('STOPPING'):
                m.d.usb += self.ulpi_stop.eq(0)

                # Check again for interruption since DIR may have
                # been asserted during the previous cycle.
                with m.If(self.ulpi_dir):
                    m.next = 'START_WRITE'
                    m.d.usb += self.ulpi_out_req.eq(0)

                with m.Else():
                    m.d.usb += [
                        self.ulpi_out_req.eq(0),
                        self.done.eq(1)
                    ]
                    m.next = 'IDLE'

        return m
Ejemplo n.º 25
0
    def elaborate(self, platform):
        m = Module()
        # Parser
        parser = SPIParser(self.platform)
        m.submodules.parser = parser
        # Busy used to detect move or scanline in action
        # disabled "dispatching"
        busy = Signal()
        # Polynomal Move
        polynomal = Polynomal(self.platform)
        m.submodules.polynomal = polynomal
        if platform:
            board_spi = platform.request("debug_spi")
            spi = synchronize(m, board_spi)
            laserheadpins = platform.request("laserscanner")
            steppers = [res for res in get_all_resources(platform, "stepper")]
            bldc = platform.request("bldc")
            leds = [res.o for res in get_all_resources(platform, "led")]
            assert len(steppers) != 0
        else:
            platform = self.platform
            self.spi = SPIBus()
            self.parser = parser
            self.pol = polynomal
            spi = synchronize(m, self.spi)
            self.laserheadpins = platform.laserhead
            self.steppers = steppers = platform.steppers
            self.busy = busy
            laserheadpins = platform.laserhead
            bldc = platform.bldc
            leds = platform.leds
        # Local laser signal clones
        enable_prism = Signal()
        lasers = Signal(2)
        # Laserscan Head
        if self.simdiode:
            laserhead = DiodeSimulator(platform=platform, addfifo=False)
            lh = laserhead
            m.d.comb += [
                lh.enable_prism_in.eq(enable_prism | lh.enable_prism),
                lh.laser0in.eq(lasers[0]
                               | lh.lasers[0]),
                laserhead.laser1in.eq(lasers[1]
                                      | lh.lasers[1])
            ]
        else:
            laserhead = Laserhead(platform=platform)
            m.d.comb += laserhead.photodiode.eq(laserheadpins.photodiode)
        m.submodules.laserhead = laserhead
        if platform.name == 'Test':
            self.laserhead = laserhead
        # polynomal iterates over count
        coeffcnt = Signal(range(len(polynomal.coeff) + 1))
        # Prism motor
        prism_driver = Driver(platform)
        m.submodules.prism_driver = prism_driver
        # connect prism motor
        for idx in range(len(leds)):
            m.d.comb += leds[idx].eq(prism_driver.leds[idx])

        m.d.comb += prism_driver.enable_prism.eq(enable_prism)
        m.d.comb += [
            bldc.uL.eq(prism_driver.uL),
            bldc.uH.eq(prism_driver.uH),
            bldc.vL.eq(prism_driver.vL),
            bldc.vH.eq(prism_driver.vH),
            bldc.wL.eq(prism_driver.wL),
            bldc.wH.eq(prism_driver.wH)
        ]
        m.d.comb += [
            prism_driver.hall[0].eq(bldc.sensor0),
            prism_driver.hall[1].eq(bldc.sensor1),
            prism_driver.hall[2].eq(bldc.sensor2)
        ]
        # connect laserhead
        m.d.comb += [
            # TODO: fix removal
            # laserheadpins.pwm.eq(laserhead.pwm),
            # laserheadpins.en.eq(laserhead.enable_prism | enable_prism),
            laserheadpins.laser0.eq(laserhead.lasers[0] | lasers[0]),
            laserheadpins.laser1.eq(laserhead.lasers[1] | lasers[1]),
        ]
        # connect Parser
        m.d.comb += [
            self.read_data.eq(parser.read_data),
            laserhead.read_data.eq(parser.read_data),
            laserhead.empty.eq(parser.empty),
            self.empty.eq(parser.empty),
            parser.read_commit.eq(self.read_commit | laserhead.read_commit),
            parser.read_en.eq(self.read_en | laserhead.read_en),
            parser.read_discard.eq(self.read_discard | laserhead.read_discard)
        ]
        # connect motors
        for idx, stepper in enumerate(steppers):
            step = (polynomal.step[idx] & ((stepper.limit == 0) | stepper.dir))
            if idx != (list(platform.stepspermm.keys()).index(
                    platform.laser_axis)):
                direction = polynomal.dir[idx]
                m.d.comb += [
                    stepper.step.eq(step),
                    stepper.dir.eq(direction),
                    parser.pinstate[idx].eq(stepper.limit)
                ]
            # connect the motor in which the laserhead moves to laser core
            else:
                m.d.comb += [
                    parser.pinstate[idx].eq(stepper.limit),
                    stepper.step.eq((step & (~laserhead.process_lines))
                                    | (laserhead.step
                                       & (laserhead.process_lines))),
                    stepper.dir.eq(
                        (polynomal.dir[idx] & (~laserhead.process_lines))
                        | (laserhead.dir & (laserhead.process_lines)))
                ]
        m.d.comb += (parser.pinstate[len(steppers):].eq(
            Cat(laserhead.photodiode_t, laserhead.synchronized)))

        # update position
        stepper_d = Array(Signal() for _ in range(len(steppers)))
        for idx, stepper in enumerate(steppers):
            pos = parser.position[idx]
            m.d.sync += stepper_d[idx].eq(stepper.step)
            with m.If(stepper.limit == 1):
                m.d.sync += parser.position[idx].eq(0)
            # assuming position is signed
            # TODO: this might eat LUT, optimize
            pos_max = pow(2, pos.width - 1) - 2
            with m.Elif((pos > pos_max) | (pos < -pos_max)):
                m.d.sync += parser.position[idx].eq(0)
            with m.Elif((stepper.step == 1) & (stepper_d[idx] == 0)):
                with m.If(stepper.dir):
                    m.d.sync += pos.eq(pos + 1)
                with m.Else():
                    m.d.sync += pos.eq(pos - 1)

        # Busy signal
        m.d.comb += busy.eq(polynomal.busy | laserhead.process_lines)
        # connect spi
        m.d.comb += parser.spi.connect(spi)
        # pins you can write to
        pins = Cat(lasers, enable_prism, laserhead.synchronize)
        with m.FSM(reset='RESET', name='dispatcher'):
            with m.State('RESET'):
                m.next = 'WAIT_INSTRUCTION'
                m.d.sync += pins.eq(0)
            with m.State('WAIT_INSTRUCTION'):
                m.d.sync += [self.read_commit.eq(0), polynomal.start.eq(0)]
                with m.If((self.empty == 0) & parser.parse & (busy == 0)):
                    m.d.sync += self.read_en.eq(1)
                    m.next = 'PARSEHEAD'
            # check which instruction we r handling
            with m.State('PARSEHEAD'):
                byte0 = self.read_data[:8]
                m.d.sync += self.read_en.eq(0)
                with m.If(byte0 == INSTRUCTIONS.MOVE):
                    m.d.sync += [
                        polynomal.ticklimit.eq(self.read_data[8:]),
                        coeffcnt.eq(0)
                    ]
                    m.next = 'MOVE_POLYNOMAL'
                with m.Elif(byte0 == INSTRUCTIONS.WRITEPIN):
                    m.d.sync += [
                        pins.eq(self.read_data[8:]),
                        self.read_commit.eq(1)
                    ]
                    m.next = 'WAIT'
                with m.Elif((byte0 == INSTRUCTIONS.SCANLINE)
                            | (byte0 == INSTRUCTIONS.LASTSCANLINE)):
                    m.d.sync += [
                        self.read_discard.eq(1),
                        laserhead.synchronize.eq(1),
                        laserhead.expose_start.eq(1)
                    ]
                    m.next = 'SCANLINE'
                with m.Else():
                    m.next = 'ERROR'
                    m.d.sync += parser.dispatcherror.eq(1)
            with m.State('MOVE_POLYNOMAL'):
                with m.If(coeffcnt < len(polynomal.coeff)):
                    with m.If(self.read_en == 0):
                        m.d.sync += self.read_en.eq(1)
                    with m.Else():
                        m.d.sync += [
                            polynomal.coeff[coeffcnt].eq(self.read_data),
                            coeffcnt.eq(coeffcnt + 1),
                            self.read_en.eq(0)
                        ]
                with m.Else():
                    m.next = 'WAIT'
                    m.d.sync += [polynomal.start.eq(1), self.read_commit.eq(1)]
            with m.State('SCANLINE'):
                m.d.sync += [
                    self.read_discard.eq(0),
                    laserhead.expose_start.eq(0)
                ]
                m.next = 'WAIT'
            # NOTE: you need to wait for busy to be raised
            #       in time
            with m.State('WAIT'):
                m.d.sync += polynomal.start.eq(0)
                m.next = 'WAIT_INSTRUCTION'
            # NOTE: system never recovers user must reset
            with m.State('ERROR'):
                m.next = 'ERROR'
        return m
Ejemplo n.º 26
0
 def elaborate(self, platform):
     m = Module()
     if platform and self.top:
         board_spi = platform.request("debug_spi")
         spi2 = synchronize(m, board_spi)
         m.d.comb += self.spi.connect(spi2)
     if self.platform:
         platform = self.platform
     spi = self.spi
     interf = SPICommandInterface(command_size=COMMAND_BYTES * 8,
                                  word_size=WORD_BYTES * 8)
     m.d.comb += interf.spi.connect(spi)
     m.submodules.interf = interf
     # FIFO connection
     fifo = TransactionalizedFIFO(width=MEMWIDTH, depth=platform.memdepth)
     if platform.name == 'Test':
         self.fifo = fifo
     m.submodules.fifo = fifo
     m.d.comb += [
         self.read_data.eq(fifo.read_data),
         fifo.read_commit.eq(self.read_commit),
         fifo.read_discard.eq(self.read_discard),
         fifo.read_en.eq(self.read_en),
         self.empty.eq(fifo.empty)
     ]
     # Parser
     mtrcntr = Signal(range(platform.motors))
     wordsreceived = Signal(range(wordsinmove(platform) + 1))
     error = Signal()
     # Peripheral state
     state = Signal(8)
     m.d.sync += [
         state[STATE.PARSING].eq(self.parse),
         state[STATE.FULL].eq(fifo.space_available <= 1),
         state[STATE.ERROR].eq(self.dispatcherror | error)
     ]
     # remember which word we are processing
     instruction = Signal(8)
     with m.FSM(reset='RESET', name='parser'):
         with m.State('RESET'):
             m.d.sync += [
                 self.parse.eq(1),
                 wordsreceived.eq(0),
                 error.eq(0)
             ]
             m.next = 'WAIT_COMMAND'
         with m.State('WAIT_COMMAND'):
             with m.If(interf.command_ready):
                 word = Cat(state[::-1], self.pinstate[::-1])
                 with m.If(interf.command == COMMANDS.EMPTY):
                     m.next = 'WAIT_COMMAND'
                 with m.Elif(interf.command == COMMANDS.START):
                     m.next = 'WAIT_COMMAND'
                     m.d.sync += self.parse.eq(1)
                 with m.Elif(interf.command == COMMANDS.STOP):
                     m.next = 'WAIT_COMMAND'
                     m.d.sync += self.parse.eq(0)
                 with m.Elif(interf.command == COMMANDS.WRITE):
                     m.d.sync += interf.word_to_send.eq(word)
                     with m.If(state[STATE.FULL] == 0):
                         m.next = 'WAIT_WORD'
                     with m.Else():
                         m.next = 'WAIT_COMMAND'
                 with m.Elif(interf.command == COMMANDS.READ):
                     m.d.sync += interf.word_to_send.eq(word)
                     m.next = 'WAIT_COMMAND'
                 with m.Elif(interf.command == COMMANDS.POSITION):
                     # position is requested multiple times for multiple
                     # motors
                     with m.If(mtrcntr < platform.motors - 1):
                         m.d.sync += mtrcntr.eq(mtrcntr + 1)
                     with m.Else():
                         m.d.sync += mtrcntr.eq(0)
                     m.d.sync += interf.word_to_send.eq(
                         self.position[mtrcntr])
                     m.next = 'WAIT_COMMAND'
         with m.State('WAIT_WORD'):
             with m.If(interf.word_complete):
                 byte0 = interf.word_received[:8]
                 with m.If(wordsreceived == 0):
                     with m.If((byte0 > 0) & (byte0 < 6)):
                         m.d.sync += [
                             instruction.eq(byte0),
                             fifo.write_en.eq(1),
                             wordsreceived.eq(wordsreceived + 1),
                             fifo.write_data.eq(interf.word_received)
                         ]
                         m.next = 'WRITE'
                     with m.Else():
                         m.d.sync += error.eq(1)
                         m.next = 'WAIT_COMMAND'
                 with m.Else():
                     m.d.sync += [
                         fifo.write_en.eq(1),
                         wordsreceived.eq(wordsreceived + 1),
                         fifo.write_data.eq(interf.word_received)
                     ]
                     m.next = 'WRITE'
         with m.State('WRITE'):
             m.d.sync += fifo.write_en.eq(0)
             wordslaser = wordsinscanline(
                 params(platform)['BITSINSCANLINE'])
             wordsmotor = wordsinmove(platform)
             with m.If(((instruction == INSTRUCTIONS.MOVE)
                        & (wordsreceived >= wordsmotor))
                       | (instruction == INSTRUCTIONS.WRITEPIN)
                       | (instruction == INSTRUCTIONS.LASTSCANLINE)
                       | ((instruction == INSTRUCTIONS.SCANLINE)
                          & (wordsreceived >= wordslaser))):
                 m.d.sync += [wordsreceived.eq(0), fifo.write_commit.eq(1)]
                 m.next = 'COMMIT'
             with m.Else():
                 m.next = 'WAIT_COMMAND'
         with m.State('COMMIT'):
             m.d.sync += fifo.write_commit.eq(0)
             m.next = 'WAIT_COMMAND'
     return m
Ejemplo n.º 27
0
    def elaborate(self, platform):
        m = Module()
        sync = m.d.sync
        comb = m.d.comb

        cfg = self.mem_config
        # TODO XXX self.no_match on decoder
        m.submodules.bridge = GenericInterfaceToWishboneMasterBridge(
            generic_bus=self.generic_bus, wb_bus=self.wb_bus)
        self.decoder = m.submodules.decoder = WishboneBusAddressDecoder(
            wb_bus=self.wb_bus, word_size=cfg.word_size)
        self.initialize_mmio_devices(self.decoder, m)
        pe = m.submodules.pe = self.pe = PriorityEncoder(width=len(self.ports))
        sorted_ports = [port for priority, port in sorted(self.ports.items())]

        # force 'elaborate' invocation for all mmio modules.
        for mmio_module, addr_space in self.mmio_cfg:
            setattr(m.submodules, addr_space.basename, mmio_module)

        addr_translation_en = self.addr_translation_en = Signal()
        bus_free_to_latch = self.bus_free_to_latch = Signal(reset=1)

        if self.with_addr_translation:
            m.d.comb += addr_translation_en.eq(self.csr_unit.satp.mode & (
                self.exception_unit.current_priv_mode == PrivModeBits.USER))
        else:
            m.d.comb += addr_translation_en.eq(False)

        with m.If(~addr_translation_en):
            # when translation enabled, 'bus_free_to_latch' is low during page-walk.
            # with no translation it's simpler - just look at the main bus.
            m.d.comb += bus_free_to_latch.eq(~self.generic_bus.busy)

        with m.If(bus_free_to_latch):
            # no transaction in-progress
            for i, p in enumerate(sorted_ports):
                m.d.sync += pe.i[i].eq(p.en)

        virtual_req_bus_latch = LoadStoreInterface()
        phys_addr = self.phys_addr = Signal(32)

        # translation-unit controller signals.
        start_translation = self.start_translation = Signal()
        translation_ack = self.translation_ack = Signal()
        gb = self.generic_bus

        with m.If(self.decoder.no_match & self.wb_bus.cyc):
            m.d.comb += self.exception_unit.badaddr.eq(gb.addr)
            with m.If(gb.store):
                m.d.comb += self.exception_unit.m_store_error.eq(1)
            with m.Elif(gb.is_fetch):
                m.d.comb += self.exception_unit.m_fetch_error.eq(1)
            with m.Else():
                m.d.comb += self.exception_unit.m_load_error.eq(1)

        with m.If(~pe.none):
            # transaction request occured
            for i, priority in enumerate(sorted_ports):
                with m.If(pe.o == i):
                    bus_owner_port = sorted_ports[i]
                    with m.If(~addr_translation_en):
                        # simple case, no need to calculate physical address
                        comb += gb.connect(bus_owner_port)
                    with m.Else():
                        # page-walk performs multiple memory operations - will reconnect 'generic_bus' multiple times
                        with m.FSM():
                            first = self.first = Signal(
                            )  # TODO get rid of that
                            with m.State("TRANSLATE"):
                                comb += [
                                    start_translation.eq(1),
                                    bus_free_to_latch.eq(0),
                                ]
                                sync += virtual_req_bus_latch.connect(
                                    bus_owner_port,
                                    exclude=[
                                        name
                                        for name, _, dir in generic_bus_layout
                                        if dir == DIR_FANOUT
                                    ])
                                with m.If(
                                        translation_ack
                                ):  # wait for 'phys_addr' to be set by page-walk algorithm.
                                    m.next = "REQ"
                                sync += first.eq(1)
                            with m.State("REQ"):
                                comb += gb.connect(bus_owner_port,
                                                   exclude=["addr"])
                                comb += gb.addr.eq(
                                    phys_addr)  # found by page-walk
                                with m.If(first):
                                    sync += first.eq(0)
                                with m.Else():
                                    # without 'first' signal '~gb.busy' would be high at the very beginning
                                    with m.If(~gb.busy):
                                        comb += bus_free_to_latch.eq(1)
                                        m.next = "TRANSLATE"

        req_is_write = Signal()
        pte = self.pte = Record(pte_layout)
        vaddr = Record(virt_addr_layout)
        comb += [
            req_is_write.eq(virtual_req_bus_latch.store),
            vaddr.eq(virtual_req_bus_latch.addr),
        ]

        @unique
        class Issue(IntEnum):
            OK = 0
            PAGE_INVALID = 1
            WRITABLE_NOT_READABLE = 2
            LACK_PERMISSIONS = 3
            FIRST_ACCESS = 4
            MISALIGNED_SUPERPAGE = 5
            LEAF_IS_NO_LEAF = 6

        self.error_code = Signal(Issue)

        def error(code: Issue):
            m.d.sync += self.error_code.eq(code)

        # Code below implements algorithm 4.3.2 in Risc-V Privileged specification, v1.10
        sv32_i = Signal(reset=1)
        root_ppn = self.root_ppn = Signal(22)

        if not self.with_addr_translation:
            return m

        with m.FSM():
            with m.State("IDLE"):
                with m.If(start_translation):
                    sync += sv32_i.eq(1)
                    sync += root_ppn.eq(self.csr_unit.satp.ppn)
                    m.next = "TRANSLATE"
            with m.State("TRANSLATE"):
                vpn = self.vpn = Signal(10)
                comb += vpn.eq(Mux(
                    sv32_i,
                    vaddr.vpn1,
                    vaddr.vpn0,
                ))
                comb += [
                    gb.en.eq(1),
                    gb.addr.eq(Cat(Const(0, 2), vpn, root_ppn)),
                    gb.store.eq(0),
                    gb.mask.eq(0b1111),  # TODO use -1
                ]
                with m.If(gb.ack):
                    sync += pte.eq(gb.read_data)
                    m.next = "PROCESS_PTE"
            with m.State("PROCESS_PTE"):
                with m.If(~pte.v):
                    error(Issue.PAGE_INVALID)
                with m.If(pte.w & ~pte.r):
                    error(Issue.WRITABLE_NOT_READABLE)

                is_leaf = lambda pte: pte.r | pte.x
                with m.If(is_leaf(pte)):
                    with m.If(~pte.u & (self.exception_unit.current_priv_mode
                                        == PrivModeBits.USER)):
                        error(Issue.LACK_PERMISSIONS)
                    with m.If(~pte.a | (req_is_write & ~pte.d)):
                        error(Issue.FIRST_ACCESS)
                    with m.If(sv32_i.bool() & pte.ppn0.bool()):
                        error(Issue.MISALIGNED_SUPERPAGE)
                    # phys_addr could be 34 bits long, but our interconnect is 32-bit long.
                    # below statement cuts lowest two bits of r-value.
                    sync += phys_addr.eq(
                        Cat(vaddr.page_offset, pte.ppn0, pte.ppn1))
                with m.Else():  # not a leaf
                    with m.If(sv32_i == 0):
                        error(Issue.LEAF_IS_NO_LEAF)
                    sync += root_ppn.eq(
                        Cat(pte.ppn0,
                            pte.ppn1))  # pte a is pointer to the next level
                m.next = "NEXT"
            with m.State("NEXT"):
                # Note that we cannot check 'sv32_i == 0', becuase superpages can be present.
                with m.If(is_leaf(pte)):
                    sync += sv32_i.eq(1)
                    comb += translation_ack.eq(
                        1)  # notify that 'phys_addr' signal is set
                    m.next = "IDLE"
                with m.Else():
                    sync += sv32_i.eq(0)
                    m.next = "TRANSLATE"
        return m