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

        # This state machine recognizes sequences of 6 bits and drops the 7th
        # bit.  The fsm implements a counter in a series of several states.
        # This is intentional to help absolutely minimize the levels of logic
        # used.
        drop_bit = Signal(1)

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

            for i in range(6):
                with m.State(f"D{i}"):
                    with m.If(self.i_valid):
                        with m.If(self.i_data):
                            # Receiving '1' increments the bitstuff counter.
                            m.next = (f"D{i + 1}")
                        with m.Else():
                            # Receiving '0' resets the bitstuff counter.
                            m.next = "D0"

            with m.State("D6"):
                with m.If(self.i_valid):
                    m.d.comb += drop_bit.eq(1)
                    # Reset the bitstuff counter, drop the data.
                    m.next = "D0"

        m.d.usb_io += [
            self.o_data.eq(self.i_data),
            self.o_stall.eq(drop_bit | ~self.i_valid),
            self.o_error.eq(drop_bit & self.i_data & self.i_valid),
        ]

        return m
Ejemplo n.º 2
0
    def elab(self, m: Module):
        num_words = Signal(range(Constants.MAX_INPUT_WORDS + 1))
        index = Signal(range(Constants.MAX_INPUT_WORDS))
        reset = Signal()
        m.d.comb += reset.eq(self.num_words_input.valid)
        memory = WideReadMemory(depth=Constants.MAX_INPUT_WORDS)
        m.submodules['memory'] = memory

        with m.FSM(reset="RESET"):
            with m.State("RESET"):
                m.d.sync += num_words.eq(0)
                m.d.sync += index.eq(0)
                m.d.sync += self.data_output.valid.eq(0)
                m.next = "NUM_WORDS"
            with m.State("NUM_WORDS"):
                m.d.comb += self.num_words_input.ready.eq(1)
                with m.If(self.num_words_input.is_transferring()):
                    m.d.sync += num_words.eq(self.num_words_input.payload)
                    m.next = "WRITING"
            with m.State("WRITING"):
                self.handle_writing(m, memory, num_words, index)
                with m.If(reset):
                    m.next = "RESET"
            with m.State("READING"):
                self.handle_reading(m, memory, num_words, index, reset)
                with m.If(reset):
                    m.next = "RESET"
Ejemplo n.º 3
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.º 4
0
    def elaborate(self, platform):
        m = Module()
        comb = m.d.comb

        with m.FSM():
            with m.State("WB_SLV_TRY_HANDLE"):
                comb += self.wb_bus.ack.eq(0)
                with m.If(self.wb_bus.cyc):
                    self.owner.handle_transaction(m)
                    with m.If(self.owner.get_handled_signal()):
                        m.next = "WB_SLV_DONE"
            with m.State("WB_SLV_DONE"):
                dat_r = self.owner.get_dat_r()
                comb += [
                    self.wb_bus.dat_r.eq(dat_r),
                    self.wb_bus.ack.eq(1),
                ]
                m.next = "WB_SLV_TRY_HANDLE"

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

        # Counter that stores how many cycles we've spent in reset.
        cycles_in_reset = Signal(range(0, self.reset_length_cycles))

        reset_state = 'RESETTING' if self.power_on_reset else 'IDLE'
        with m.FSM(reset=reset_state, domain='sync') as fsm:

            # Drive the PHY reset whenever we're in the RESETTING cycle.
            m.d.comb += [
                self.phy_reset.eq(fsm.ongoing('RESETTING')),
                self.phy_stop.eq(~fsm.ongoing('IDLE'))
            ]

            with m.State('IDLE'):
                m.d.sync += cycles_in_reset.eq(0)

                # Wait for a reset request.
                with m.If(self.trigger):
                    m.next = 'RESETTING'

            # RESETTING: hold the reset line active for the given amount of time
            with m.State('RESETTING'):
                m.d.sync += cycles_in_reset.eq(cycles_in_reset + 1)

                with m.If(cycles_in_reset + 1 == self.reset_length_cycles):
                    m.d.sync += cycles_in_reset.eq(0)
                    m.next = 'DEFERRING_STARTUP'

            # DEFERRING_STARTUP: Produce a signal that will defer startup for
            # the provided amount of time. This allows line state to stabilize
            # before the PHY will start interacting with us.
            with m.State('DEFERRING_STARTUP'):
                m.d.sync += cycles_in_reset.eq(cycles_in_reset + 1)

                with m.If(cycles_in_reset + 1 == self.stop_length_cycles):
                    m.d.sync += cycles_in_reset.eq(0)
                    m.next = 'IDLE'

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

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

            for i in range(5):

                with m.State(f"D{i}"):
                    # Receiving '1' increments the bitstuff counter.
                    with m.If(self.i_data):
                        m.next = f"D{i+1}"

                    # Receiving '0' resets the bitstuff counter.
                    with m.Else():
                        m.next = "D0"

            with m.State("D5"):
                with m.If(self.i_data):

                    # There's a '1', so indicate we might stall on the next loop.
                    m.d.comb += self.o_will_stall.eq(1),
                    m.next = "D6"

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

            with m.State("D6"):
                m.d.comb += stuff_bit.eq(1)
                m.next = "D0"

        m.d.comb += [self.o_stall.eq(stuff_bit)]

        # flop outputs
        with m.If(stuff_bit):
            m.d.usb += self.o_data.eq(0),
        with m.Else():
            m.d.usb += self.o_data.eq(self.i_data)

        return m
Ejemplo n.º 7
0
    def elaborate(self, platform) -> Module:
        """assemble the module"""
        m = Module()

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

        nrzi      = Signal()
        nrzi_prev = Signal()
        got_edge  = Signal()

        m.submodules.cdc = FFSynchronizer(self.nrzi_in, nrzi)
        sync += nrzi_prev.eq(nrzi)
        comb += got_edge.eq(nrzi_prev ^ nrzi)

        # we are looking for 10 non changing bits
        # and those will be ~900ns long @48kHz
        # and if we clock at not more than 100MHz
        # the counter will run up to 900ns/10ns = 90
        # so 7 bits will suffice for the counter
        sync_counter = DividingCounter(divisor=12, width=7)
        m.submodules.sync_counter = sync_counter
        bit_time = sync_counter.divided_counter_out

        with m.FSM():
            with m.State("SYNC"):
                comb += self.running.eq(0)
                sync += [
                    self.data_out.eq(0),
                    self.data_out_en.eq(0),
                    sync_counter.reset_in.eq(0)
                ]
                self.find_bit_timings(m, sync_counter, got_edge)

            with m.State("DECODE"):
                comb += self.running.eq(1)
                self.decode_nrzi(m, bit_time, got_edge, sync_counter)

        return m
Ejemplo n.º 8
0
    def elab(self, m: Module):

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

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

        # Handle output whenever ready
        m.d.comb += self.output.valid.eq(waiting_to_send)
        with m.If(self.output.is_transferring()):
            m.d.sync += waiting_to_send.eq(0)
Ejemplo n.º 9
0
    def elaborate(self, platform):
        m = Module()

        beta = self.beta
        temp = Signal(signed(self.totalbits * 2))

        n = len(self.coeff)
        j = Signal(range(1, n))
        k = Signal.like(j)
        with m.FSM(reset='INIT') as algo:
            with m.State('INIT'):
                m.d.sync += self.done.eq(0)
                for i in range(n):
                    m.d.sync += beta[i].eq(self.coeff[i])
                m.d.sync += [k.eq(0), j.eq(1)]
                m.next = 'UPDATE'
            with m.FSM('UPDATE'):
                m.d.sync += temp.eq(beta[k] * (1 - self.t) +
                                    beta[k + 1] * self.t)
                m.next = 'MULTIPLICATIONFIX'
            # Fixed point arithmetic need fix
            # see multiplication as https://vha3.github.io/FixedPoint/FixedPoint.html
            with m.FSM('MULTIPLICATIONFIX'):
                m.d.sync += beta[k].eq(
                    temp[self.fractionalbits:self.fractionalbits +
                         self.totalbits])
                with m.If(k != n - j):
                    m.d.sync += k.eq(k + 1)
                    m.next = 'UPDATE'
                with m.Else():
                    with m.If(j != n):
                        m.d.sync += j.eq(j + 1)
                        m.d.sync += k.eq(0)
                        m.next = 'UPDATE'
                    with m.Else():
                        m.next = 'FINISH'
            with m.FSM('FINISH'):
                m.d.sync += self.done.eq(1)
                m.next = 'FINISH'
        return m
Ejemplo n.º 10
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.º 11
0
    def elaborate(self, platform):
        m = Module()
        jt51 = self.jt51

        ready = Signal()
        valid = Signal()
        address = Signal(8)
        data = Signal(8)
        busy = Signal()

        m.d.comb += [
            self.input_stream.ready.eq(ready),
            valid.eq(self.input_stream.valid),
            busy.eq(jt51.dout[7]),
        ]

        with m.If(valid & ready):
            m.d.jt51 += [
                address.eq(self.input_stream.payload[8:]),
                data.eq(self.input_stream.payload[:8]),
                ready.eq(0),  # only read one FIFO entry
            ]

        with m.FSM(domain="jt51"):
            with m.State("IDLE"):
                # address comes always first
                m.d.jt51 += [
                    jt51.wr_n.eq(1),
                    # address comes always first
                    jt51.a0.eq(0),
                ]

                with m.If(valid & ~busy):
                    # read a FIFO entry
                    m.d.jt51 += ready.eq(1)
                    m.next = "FIFO_READ"

            with m.State("FIFO_READ"):
                # in this cycle, ready is 1
                # and the read values appear
                # in the next cycle
                m.d.jt51 += ready.eq(0)
                m.next = "WRITE_ADDRESS"

            with m.State("WRITE_ADDRESS"):
                m.d.jt51 += [
                    jt51.din.eq(address),
                    jt51.wr_n.eq(0),
                ]
                m.next = "ADDRESS_DONE"

            with m.State("ADDRESS_DONE"):
                m.d.jt51 += jt51.wr_n.eq(1)
                m.next = "WRITE_DATA"

            with m.State("WRITE_DATA"):
                m.d.jt51 += [
                    jt51.a0.eq(1),
                    jt51.din.eq(data),
                    jt51.wr_n.eq(0),
                ]
                m.next = "WAIT_ONE"

            # if data has been written, it takes one cycle
            # for the busy signal to appear
            with m.State("WAIT_ONE"):
                m.d.jt51 += jt51.wr_n.eq(1)
                m.next = "IDLE"

        return m
Ejemplo n.º 12
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.º 13
0
    def elaborate(self, platform):
        m = Module()
        bit_stuffing_disabled = (self.op_mode == self.OP_MODE_NO_BIT_STUFFING)

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

            # Mark ourselves as busy whenever we're not in idle.
            m.d.comb += self.busy.eq(~fsm.ongoing('IDLE'))

            # IDLE: our transmitter is ready and
            with m.State('IDLE'):
                m.d.comb += self.ulpi_stp.eq(0)

                # Start once a transmit is started, and we can access the bus.
                with m.If(self.tx_valid & self.bus_idle):

                    # If bit-stuffing is disabled, we'll need to prefix our transmission with a NOPID command.
                    # In this case, we'll never accept the first byte (as we're not ready to transmit it, yet),
                    # and thus TxReady will always be 0.
                    with m.If(bit_stuffing_disabled):
                        m.d.usb  += self.ulpi_out_req.eq(1),
                        m.d.comb += [
                            self.ulpi_data_out .eq(self.TRANSMIT_COMMAND),
                            self.tx_ready      .eq(0)
                        ]

                    # Otherwise, this transmission starts with a PID. Extract the PID from the first data byte
                    # and present it as part of the Transmit Command. In this case, the NXT signal is
                    # has the same meaning as the UTMI TxReady signal; and can be passed along directly.
                    with m.Else():
                        m.d.usb  += self.ulpi_out_req.eq(1),
                        m.d.comb += [
                            self.ulpi_data_out .eq(self.TRANSMIT_COMMAND | self.tx_data[0:4]),
                            self.tx_ready      .eq(self.ulpi_nxt)
                        ]


                    # Once the PHY has accepted the command byte, we're ready to move into our main transmit state.
                    with m.If(self.ulpi_nxt):
                        m.next = 'TRANSMIT'


            # TRANSMIT: we're in the body of a transmit; the UTMI and ULPI interface signals
            # are roughly equivalent; we'll just pass them through.
            with m.State('TRANSMIT'):
                m.d.comb += [
                    self.ulpi_data_out .eq(self.tx_data),
                    self.tx_ready      .eq(self.ulpi_nxt),
                    self.ulpi_stp      .eq(0),
                ]

                # Once the transmission has ended, we'll need to issue a ULPI stop.
                with m.If(~self.tx_valid):
                    m.d.usb += self.ulpi_out_req.eq(0),
                    m.next = 'IDLE'

                    # STOP: our packet has just terminated; we'll generate a ULPI stop event for a single cycle.
                    # [ULPI: 3.8.2.2]
                    m.d.comb += self.ulpi_stp.eq(1)

                    # If we've disabled bit stuffing, we'll want to termainate by generating a bit-stuff error.
                    with m.If(bit_stuffing_disabled):

                        # Drive 0xFF as we stop, to generate a bit-stuff error. [ULPI: 3.8.2.3]
                        m.d.comb += self.ulpi_data_out .eq(0xFF)

                    # Otherwise, we'll generate a normal stop.
                    with m.Else():
                        m.d.comb += self.ulpi_data_out .eq(0)


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

        sync_pulse = Signal(8)

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

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

        # 12MHz domain
        bitstuff_valid_data = Signal()

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

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

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

        m.submodules.nrzi = nrzi = TxNRZIEncoder()

        #
        # Transmit controller.
        #

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return m
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()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        in_stream = self.unprocessed_stream
        out_stream = self.processed_stream

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

        buffered_complete = Signal()
        buffered_invalid = Signal()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # Synchronize the USB signals at our I/O boundary.
        # Despite the assumptions made in ValentyUSB, this line rate recovery FSM
        # isn't enough to properly synchronize these inputs. We'll explicitly synchronize.
        sync_dp = synchronize(m, self._usbp, o_domain="usb_io")
        sync_dn = synchronize(m, self._usbn, o_domain="usb_io")

        #######################################################################
        # Line State Recovery State Machine
        #
        # The receive path doesn't use a differential receiver.  Because of
        # this there is a chance that one of the differential pairs will appear
        # to have changed to the new state while the other is still in the old
        # state.  The following state machine detects transitions and waits an
        # extra sampling clock before decoding the state on the differential
        # pair.  This transition period  will only ever last for one clock as
        # long as there is no noise on the line.  If there is enough noise on
        # the line then the data may be corrupted and the packet will fail the
        # data integrity checks.
        #
        dpair = Cat(sync_dp, sync_dn)

        # output signals for use by the clock recovery stage
        line_state_in_transition = Signal()

        with m.FSM(domain="usb_io") as fsm:
            m.d.usb_io += [
                self.line_state_se0.eq(fsm.ongoing("SE0")),
                self.line_state_se1.eq(fsm.ongoing("SE1")),
                self.line_state_dj.eq(fsm.ongoing("DJ")),
                self.line_state_dk.eq(fsm.ongoing("DK")),
            ]

            # If we are in a transition state, then we can sample the pair and
            # move to the next corresponding line state.
            with m.State("DT"):
                m.d.comb += line_state_in_transition.eq(1)

                with m.Switch(dpair):
                    with m.Case(0b10):
                        m.next = "DJ"
                    with m.Case(0b01):
                        m.next = "DK"
                    with m.Case(0b00):
                        m.next = "SE0"
                    with m.Case(0b11):
                        m.next = "SE1"

            # If we are in a valid line state and the value of the pair changes,
            # then we need to move to the transition state.
            with m.State("DJ"):
                with m.If(dpair != 0b10):
                    m.next = "DT"

            with m.State("DK"):
                with m.If(dpair != 0b01):
                    m.next = "DT"

            with m.State("SE0"):
                with m.If(dpair != 0b00):
                    m.next = "DT"

            with m.State("SE1"):
                with m.If(dpair != 0b11):
                    m.next = "DT"

        #######################################################################
        # Clock and Data Recovery
        #
        # The DT state from the line state recovery state machine is used to align to
        # transmit clock.  The line state is sampled in the middle of the bit time.
        #
        # Example of signal relationships
        # -------------------------------
        # line_state        DT  DJ  DJ  DJ  DT  DK  DK  DK  DK  DK  DK  DT  DJ  DJ  DJ
        # line_state_valid  ________----____________----____________----________----____
        # bit_phase         0   0   1   2   3   0   1   2   3   0   1   2   0   1   2
        #

        # We 4x oversample, so make the line_state_phase have
        # 4 possible values.
        line_state_phase = Signal(2)
        m.d.usb_io += self.line_state_valid.eq(line_state_phase == 1)

        with m.If(line_state_in_transition):
            m.d.usb_io += [
                # re-align the phase with the incoming transition
                line_state_phase.eq(0),

                # make sure we never assert valid on a transition
                self.line_state_valid.eq(0),
            ]
        with m.Else():
            # keep tracking the clock by incrementing the phase
            m.d.usb_io += line_state_phase.eq(line_state_phase + 1)

        return m
Ejemplo n.º 22
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.º 23
0
    def elaborate(self, platform):

        m = Module()
        spi = self.spi

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # If we're standalone, generate the things we need.
        if self.standalone:

            # Create our tokenizer...
            m.submodules.tokenizer = tokenizer = USBTokenDetector(
                utmi=self.utmi)
            m.d.comb += tokenizer.interface.connect(self.tokenizer)

            # ... and our timer.
            m.submodules.timer = timer = USBInterpacketTimer()
            timer.add_interface(self.timer)

            m.d.comb += timer.speed.eq(self.speed)

        # Create a data-packet-deserializer, which we'll use to capture the
        # contents of the setup data packets.
        m.submodules.data_handler = data_handler = \
            USBDataPacketDeserializer(utmi=self.utmi, max_packet_size=8, create_crc_generator=self.standalone)
        m.d.comb += self.data_crc.connect(data_handler.data_crc)

        # Instruct our interpacket timer to begin counting when we complete receiving
        # our setup packet. This will allow us to track interpacket delays.
        m.d.comb += self.timer.start.eq(data_handler.new_packet)

        # Keep our output signals de-asserted unless specified.
        m.d.usb += [
            self.packet.received.eq(0),
        ]

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

            # IDLE -- we haven't yet detected a SETUP transaction directed at us
            with m.State('IDLE'):
                pid_matches = (self.tokenizer.pid == self.SETUP_PID)

                # If we're just received a new SETUP token addressed to us,
                # the next data packet is going to be for us.
                with m.If(pid_matches & self.tokenizer.new_token):
                    m.next = 'READ_DATA'

            # READ_DATA -- we've just seen a SETUP token, and are waiting for the
            # data payload of the transaction, which contains the setup packet.
            with m.State('READ_DATA'):

                # If we receive a token packet before we receive a DATA packet,
                # this is a PID mismatch. Bail out and start over.
                with m.If(self.tokenizer.new_token):
                    m.next = 'IDLE'

                # If we have a new packet, parse it as setup data.
                with m.If(data_handler.new_packet):

                    # If we got exactly eight bytes, this is a valid setup packet.
                    with m.If(data_handler.length == 8):

                        # Collect the signals that make up our bmRequestType [USB2, 9.3].
                        request_type = Cat(self.packet.recipient,
                                           self.packet.type,
                                           self.packet.is_in_request)

                        m.d.usb += [

                            # Parse the setup data itself...
                            request_type.eq(data_handler.packet[0]),
                            self.packet.request.eq(data_handler.packet[1]),
                            self.packet.value.eq(
                                Cat(data_handler.packet[2],
                                    data_handler.packet[3])),
                            self.packet.index.eq(
                                Cat(data_handler.packet[4],
                                    data_handler.packet[5])),
                            self.packet.length.eq(
                                Cat(data_handler.packet[6],
                                    data_handler.packet[7])),

                            # ... and indicate that we have new data.
                            self.packet.received.eq(1),
                        ]

                        # We'll now need to wait a receive-transmit delay before initiating our ACK.
                        # Per the USB 2.0 and ULPI 1.1 specifications:
                        #   - A HS device needs to wait 8 HS bit periods before transmitting [USB2, 7.1.18.2].
                        #     Each ULPI cycle is 8 HS bit periods, so we'll only need to wait one cycle.
                        #   - We'll use our interpacket delay timer for everything else.
                        with m.If(self.timer.tx_allowed
                                  | (self.speed == USBSpeed.HIGH)):

                            # If we're a high speed device, we only need to wait for a single ULPI cycle.
                            # Processing delays mean we've already met our interpacket delay; and we can ACK
                            # immediately.
                            m.d.comb += self.ack.eq(1)
                            m.next = "IDLE"

                        # For other cases, handle the interpacket delay by waiting.
                        with m.Else():
                            m.next = "INTERPACKET_DELAY"

                    # Otherwise, this isn't; and we should ignore it. [USB2, 8.5.3]
                    with m.Else():
                        m.next = "IDLE"

            # INTERPACKET -- wait for an inter-packet delay before responding
            with m.State('INTERPACKET_DELAY'):

                # ... and once it equals zero, ACK and return to idle.
                with m.If(self.timer.tx_allowed):
                    m.d.comb += self.ack.eq(1)
                    m.next = "IDLE"

        return m
Ejemplo n.º 27
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.º 28
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.º 29
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.º 30
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