Beispiel #1
0
    def __init__(self):
        self.submodules.ev = ev.EventManager()
        self.ev.submodules.error = ev.EventSourcePulse()
        self.ev.submodules.packet = ev.EventSourcePulse()
        self.ev.finalize()

        self.trigger = self.ev.packet.trigger

        # Last PID?
        self.last_tok = CSRStatus(2)

        # How to respond to requests;
        #  - 10 - No response
        #  - 00 - ACK
        #  - 01 - NAK
        #  - 11 - STALL
        self.respond = CSRStorage(2, write_from_dev=True)

        self.response = Signal(2)
        self.reset = Signal()
        self.comb += [
            self.response.eq(
                Cat(
                    self.respond.storage[0] | self.ev.packet.pending,
                    self.respond.storage[1],
                )),
        ]
        self.comb += [
            self.respond.dat_w.eq(EndpointResponse.NAK),
            self.respond.we.eq(self.reset),
        ]

        self.dtb = CSRStorage(1, write_from_dev=True)
        self.comb += [
            self.dtb.dat_w.eq(~self.dtb.storage | self.reset),
        ]
        # When triggered, flip the data toggle bit
        toggle = Signal()
        self.sync += [
            If(
                self.trigger | self.reset,
                If(
                    ~toggle,
                    toggle.eq(1),
                    self.dtb.we.eq(1),
                ).Else(self.dtb.we.eq(0), ),
            ).Else(
                self.dtb.we.eq(0),
                toggle.eq(0),
            ),
        ]

        self.submodules.fake = FakeFifo()
        self.ibuf = None
        self.obuf = None
Beispiel #2
0
    def __init__(self, pads, debugging=False):
        self.intro = ModuleDoc("""Fomu Touchpads

        Fomu has four single-ended exposed pads on its side.  These pads are designed
        to be connected to some captouch block, or driven in a resistive touch mode
        in order to get simple touchpad support.

        This block attempts to implement capacative touch, while still providing
        backwards-compatibility with the original Fomu touchpad interface.

        More research will need to be done in order to determine sane defaults for the
        trigger levels.
        """)

        cap_signal_size = 8

        touch1 = TSTriple()
        touch2 = TSTriple()
        touch3 = TSTriple()
        touch4 = TSTriple()
        self.specials += touch1.get_tristate(pads.t1)
        self.specials += touch2.get_tristate(pads.t2)
        self.specials += touch3.get_tristate(pads.t3)
        self.specials += touch4.get_tristate(pads.t4)
        ios = [touch1, touch2, touch3, touch4]

        self.o      = CSRStorage(4, description="Output values for pads 1-4", fields=[
            CSRField("o1", description="Output value for pad 1"),
            CSRField("o2", description="Output value for pad 2"),
            CSRField("o3", description="Output value for pad 3"),
            CSRField("o4", description="Output value for pad 4"),
        ])
        self.oe     = CSRStorage(4, description="Output enable control for pads 1-4", fields=[
            CSRField("oe1", description="Output Enable value for pad 1"),
            CSRField("oe2", description="Output Enable value for pad 2"),
            CSRField("oe3", description="Output Enable value for pad 3"),
            CSRField("oe4", description="Output Enable value for pad 4"),
        ])
        self.i      = CSRStatus(4, description="Input value for pads 1-4", fields=[
            CSRField("i1", description="Input value for pad 1"),
            CSRField("i2", description="Input value for pad 2"),
            CSRField("i3", description="Input value for pad 3"),
            CSRField("i4", description="Input value for pad 4"),
        ])
        self.capen  = CSRStorage(4, description="Enable captouch for pads 1-4", fields=[
            CSRField("t1", description="Enable captouch for pad 1"),
            CSRField("t2", description="Enable captouch for pad 2"),
            CSRField("t3", description="Enable captouch for pad 3"),
            CSRField("t4", description="Enable captouch for pad 4"),
        ])

        cper = 524288
        cap_count_len = 20
        if debugging:
            cap_count_len = 32
            self.cper   = CSRStorage(cap_count_len, description="""The number of clock cycles for one sample period

            The hardware will count how many times the touchpad discharges within this sample
            period and reflect that value in the corresponding `count` register.""", reset=524288)
            cper = self.cper.storage

        self.cstat  = CSRStatus(4, description="Current status of the captouch buttons", fields=[
            CSRField("s1", description="State of pad 1"),
            CSRField("s2", description="State of pad 2"),
            CSRField("s3", description="State of pad 3"),
            CSRField("s4", description="State of pad 4"),
        ])

        cpress = 0x0a
        crel = 0x03
        if debugging:
            self.cpress = CSRStorage(cap_signal_size, reset=0x0a, description="Count threshold for triggering a ``press`` event")
            cpress = self.cpress.storage
            self.crel   = CSRStorage(cap_signal_size, reset=0x03, description="Count threshold for triggering a ``release`` event")
            crel = self.crel.storage
        if debugging:
            self.c1     = CSRStatus(cap_signal_size, description="Count of events for pad 1")
            self.c2     = CSRStatus(cap_signal_size, description="Count of events for pad 2")
            self.c3     = CSRStatus(cap_signal_size, description="Count of events for pad 3")
            self.c4     = CSRStatus(cap_signal_size, description="Count of events for pad 4")

        cap_count = Signal(cap_count_len)
        cap1_count = Signal(cap_signal_size)
        cap2_count = Signal(cap_signal_size)
        cap3_count = Signal(cap_signal_size)
        cap4_count = Signal(cap_signal_size)

        self.submodules.ev = ev.EventManager()
        self.ev.submodules.touch = ev.EventSourcePulse(name="touch", description="""
            Indicates a touch event such as a "press" or "release" has occurred.""")
        self.ev.finalize()

        ar = []
        syn = []
        cmb = []
        for num, pad in enumerate(ios, start=1):
            print("touch{}".format(num))
            if debugging:
                exec("ar.append(self.c{}.status.eq(cap{}_count))".format(num, num))
            exec("ar.append(cap{}_count.eq(0))".format(num))

            # Implement a schmitt trigger in Verilog
            # 1: Value is 1 and count > crel OR value is 0 and count > cpress
            # 0: Value is 1 and count < crel OR value is 0 and count < cpress
            exec("""ar.append(self.cstat.fields.s{}.eq(
                    (self.cstat.fields.s{} & wrap(cap{}_count > crel)) |
                    (~self.cstat.fields.s{} & wrap(cap{}_count > cpress))))""".format(num, num, num, num, num))

            exec("cmb.append(pad.o.eq(self.o.fields.o{} | self.capen.fields.t{}))".format(num, num))
            exec("cmb.append(self.i.fields.i{}.eq(pad.i))".format(num))
            exec("syn.append(cap{}_count.eq(cap{}_count + (self.capen.fields.t{} & ~pad.i)))".format(num, num, num))
            exec("syn.append(pad.oe.eq(self.oe.fields.oe{} | (self.capen.fields.t{} & ~pad.i)))".format(num, num))

        # This is used to trigger an interrupt when this value changes
        last_stat = Signal(4)

        self.sync += [
            self.ev.touch.trigger.eq(0),

            last_stat.eq(self.cstat.status),
            self.ev.touch.trigger.eq(self.cstat.status != last_stat),

            *syn,

            # Perform a captouch tick
            If(cap_count > 0,
                cap_count.eq(cap_count - 1),
            ).Else(
                cap_count.eq(cper),
                *ar,
            ),
        ]

        self.comb += [
            *cmb,
        ]
Beispiel #3
0
    def __init__(self, usb_core):

        self.submodules.data_buf = buf = ResetInserter()(fifo.SyncFIFOBuffered(
            width=8, depth=66))

        self.data = data = CSRStatus(fields=[
            CSRField("data",
                     8,
                     description="The top byte of the receive FIFO."),
        ],
                                     description="""
                Data received from the host will go into a FIFO.  This register
                reflects the contents of the top byte in that FIFO.  Reading from
                this register advances the FIFO pointer.""")

        self.ctrl = ctrl = CSRStorage(fields=[
            CSRField(
                "epno",
                4,
                description=
                "The endpoint number to update the ``enable`` and ``status`` bits for."
            ),
            CSRField(
                "enable",
                description="Write a ``1`` here to enable receiving data"),
            CSRField(
                "reset",
                pulse=True,
                description="Write a ``1`` here to reset the ``OUT`` handler"),
            CSRField("stall",
                     description="Write a ``1`` here to stall an endpoint"),
        ],
                                      description="""
                Controls for receiving packet data.  To enable an endpoint, write its value to ``epno``,
                with the ``enable`` bit set to ``1`` to enable an endpoint, or ``0`` to disable it.
                Resetting the OutHandler will set all ``enable`` bits to 0.

                Similarly, you can adjust the ``STALL`` state by setting or clearing the ``stall`` bit."""
                                      )

        self.status = CSRStatus(
            fields=[
                CSRField(
                    "epno",
                    4,
                    description=
                    "The destination endpoint for the most recent ``OUT`` packet."
                ),
                CSRField("have",
                         description="``1`` if there is data in the FIFO."),
                CSRField("pend",
                         description="``1`` if there is an IRQ pending."),
            ],
            description="Status about the current state of the `OUT` endpoint."
        )

        self.submodules.ev = ev.EventManager()
        self.ev.submodules.packet = ev.EventSourcePulse(name="done",
                                                        description="""
            Indicates that an ``OUT`` packet has successfully been transferred
            from the host.  This bit must be cleared in order to receive
            additional packets.""")
        self.ev.finalize()

        self.usb_reset = Signal()

        self.stalled = Signal()
        self.enabled = Signal()
        stall_status = Signal(16)
        enable_status = Signal(16)
        ep_mask = Signal(16, reset=1)
        self.comb += [
            If(
                usb_core.setup | usb_core.commit,
                ep_mask.eq(1 << usb_core.endp),
            ).Else(ep_mask.eq(1 << ctrl.fields.epno), ),
            self.stalled.eq(stall_status >> usb_core.endp),
            self.enabled.eq(enable_status >> usb_core.endp),
        ]
        self.sync += [
            If(
                ctrl.fields.reset | self.usb_reset,
                stall_status.eq(0),
            ).Elif(
                usb_core.setup | (ctrl.re & ~ctrl.fields.stall),
                # If a SETUP packet comes in, clear the STALL bit.
                stall_status.eq(stall_status & ~ep_mask),
            ).Elif(
                ctrl.re,
                stall_status.eq(stall_status | ep_mask),
            ),
        ]

        # The endpoint number of the most recently received packet
        epno = Signal(4)

        # How to respond to requests:
        #  - 1 - ACK
        #  - 0 - NAK
        # Send a NAK if the buffer contains data, or if "ENABLE" has not been set.
        self.response = Signal()
        responding = Signal()
        is_out_packet = Signal()

        # Keep track of whether we're currently responding.
        self.comb += is_out_packet.eq(usb_core.tok == PID.OUT)
        self.comb += self.response.eq(self.enabled & is_out_packet
                                      & ~self.ev.packet.pending)
        self.sync += If(usb_core.poll, responding.eq(self.response))

        # Connect the buffer to the USB system
        self.data_recv_payload = Signal(8)
        self.data_recv_put = Signal()
        self.comb += [
            buf.din.eq(self.data_recv_payload),
            buf.we.eq(self.data_recv_put & responding),
            buf.reset.eq(ctrl.fields.reset),
            self.data.fields.data.eq(buf.dout),

            # When data is read, advance the FIFO
            buf.re.eq(data.we),
            self.status.fields.epno.eq(epno),
            self.status.fields.have.eq(buf.readable),
            self.status.fields.pend.eq(self.ev.packet.pending),

            # When data is successfully transferred, the buffer becomes full.
            # This is true even if "no" data was transferred, because the
            # buffer will then contain two bytes of CRC16 data.
            # Therefore, if the FIFO is readable, an interrupt must be triggered.
            self.ev.packet.trigger.eq(responding & usb_core.commit),
        ]

        # If we get a packet, turn off the "IDLE" flag and keep it off until the packet has finished.
        self.sync += [
            If(
                ctrl.fields.reset,
                enable_status.eq(0),
            ).Elif(
                usb_core.commit & responding,
                epno.eq(usb_core.endp),
                # Disable this EP when a transfer finishes
                enable_status.eq(enable_status & ~ep_mask),
                responding.eq(0),
            ).Elif(
                ctrl.re,
                # Enable or disable the EP as necessary
                If(
                    ctrl.fields.enable,
                    enable_status.eq(enable_status | ep_mask),
                ).Else(enable_status.eq(enable_status & ~ep_mask), ),
            ),
        ]
Beispiel #4
0
    def __init__(self, usb_core):
        self.dtb = Signal()

        # Keep track of the current DTB for each of the 16 endpoints
        dtbs = Signal(16, reset=0x0001)

        # A list of endpoints that are stalled
        stall_status = Signal(16)

        self.submodules.data_buf = buf = ResetInserter()(fifo.SyncFIFOBuffered(
            width=8, depth=64))

        self.data = CSRStorage(fields=[
            CSRField("data",
                     8,
                     description="The next byte to add to the queue."),
        ],
                               description="""
                Each byte written into this register gets added to an outgoing FIFO. Any
                bytes that are written here will be transmitted in the order in which
                they were added.  The FIFO queue is automatically advanced with each write.
                The FIFO queue is 64 bytes deep.  If you exceed this amount, the result is undefined."""
                               )

        self.ctrl = ctrl = CSRStorage(fields=[
            CSRField(
                "epno",
                4,
                description=
                "The endpoint number for the transaction that is queued in the FIFO."
            ),
            CSRField("reset",
                     offset=5,
                     description=
                     "Write a ``1`` here to clear the contents of the FIFO.",
                     pulse=True),
            CSRField("stall",
                     description=
                     "Write a ``1`` here to stall the EP written in ``EP``.",
                     pulse=True),
        ],
                                      description="""
                Enables transmission of data in response to ``IN`` tokens,
                or resets the contents of the FIFO.""")

        self.status = CSRStatus(fields=[
            CSRField(
                "idle",
                description=
                "This value is ``1`` if the packet has finished transmitting."
            ),
            CSRField("have",
                     offset=4,
                     description="This value is ``0`` if the FIFO is empty."),
            CSRField("pend",
                     offset=5,
                     description="``1`` if there is an IRQ pending."),
        ],
                                description="""
                Status about the IN handler.  As soon as you write to `IN_DATA`,
                ``IN_STATUS.HAVE`` should go to ``1``.""")

        self.submodules.ev = ev.EventManager()
        self.ev.submodules.packet = ev.EventSourcePulse(name="done",
                                                        description="""
            Indicates that the host has successfully transferred an ``IN`` packet,
            and that the FIFO is now empty.
            """)
        self.ev.finalize()

        # Control bits
        ep_stall_mask = Signal(16)
        self.comb += [
            ep_stall_mask.eq(1 << ctrl.fields.epno),
        ]

        # Keep track of which endpoints are currently stalled
        self.stalled = Signal()
        self.comb += self.stalled.eq(stall_status >> usb_core.endp)
        self.sync += [
            If(
                ctrl.fields.reset,
                stall_status.eq(0),
            ).Elif(
                usb_core.setup | (ctrl.re & ~ctrl.fields.stall),
                # If a SETUP packet comes in, clear the STALL bit.
                stall_status.eq(stall_status & ~ep_stall_mask),
            ).Elif(
                ctrl.re,
                stall_status.eq(stall_status | ep_stall_mask),
            ),
        ]

        # How to respond to requests:
        #  - 0 - ACK
        #  - 1 - NAK
        self.response = Signal()

        # This value goes "1" when data is pending, and returns to "0" when it's done.
        queued = Signal()
        was_queued = Signal()

        # This goes to "1" when "queued" is 1 when a "start" occurs.  It is used
        # to avoid skipping packets when a packet is queued during a transmission.
        transmitted = Signal()

        self.dtb_reset = Signal()
        self.comb += [
            buf.reset.eq(ctrl.fields.reset
                         | (usb_core.commit & transmitted & queued)),
        ]

        # Outgoing data will be placed on this signal
        self.data_out = Signal(8)

        # This is "1" if `data_out` contains data
        self.data_out_have = Signal()

        # Pulse this to advance the data output
        self.data_out_advance = Signal()

        # Used to detect when an IN packet finished
        is_our_packet = Signal()
        is_in_packet = Signal()

        self.comb += [
            # We will respond with "ACK" if the register matches the current endpoint number
            self.response.eq(queued & is_our_packet & is_in_packet),

            # Wire up the "status" register
            self.status.fields.have.eq(buf.readable),
            self.status.fields.idle.eq(~queued),
            self.status.fields.pend.eq(self.ev.packet.pending),

            # Cause a trigger event when the `queued` value goes to 0
            self.ev.packet.trigger.eq(~queued & was_queued),
            self.dtb.eq(dtbs >> usb_core.endp),
            self.data_out.eq(buf.dout),
            self.data_out_have.eq(buf.readable),
            buf.re.eq(self.data_out_advance & is_in_packet & is_our_packet),
            buf.we.eq(self.data.re),
            buf.din.eq(self.data.storage),
            is_our_packet.eq(usb_core.endp == ctrl.fields.epno),
            is_in_packet.eq(usb_core.tok == PID.IN),
        ]

        self.sync += [
            If(
                ctrl.fields.reset,
                queued.eq(0),
                was_queued.eq(0),
                transmitted.eq(0),
                dtbs.eq(0x0001),
            ).Elif(
                self.dtb_reset,
                dtbs.eq(dtbs | 1),
            )
            # When the user updates the `ctrl` register, enable writing.
            .Elif(
                ctrl.re & ~ctrl.fields.stall,
                queued.eq(1),
            ).Elif(
                usb_core.poll & self.response,
                transmitted.eq(1),
            )
            # When the USB core finishes operating on this packet,
            # de-assert the queue flag
            .Elif(
                usb_core.commit & transmitted & self.response & ~self.stalled,
                queued.eq(0),
                transmitted.eq(0),
                # Toggle the "DTB" line if we transmitted data
                dtbs.eq(dtbs ^ (1 << ctrl.fields.epno)),
            ).Else(was_queued.eq(queued), ),
        ]
Beispiel #5
0
    def __init__(self, usb_core):

        self.reset = Signal()
        self.begin = Signal()
        self.epno = epno = Signal()
        self.usb_reset = Signal()

        # Register Interface
        self.data = data = CSRStatus(
            fields=[
                CSRField("data",
                         8,
                         description="The next byte of ``SETUP`` data")
            ],
            description=
            """Data from the last ``SETUP`` transactions.  It will be 10 bytes long, because
                           it will include the CRC16.  This is a FIFO, and the queue is advanced automatically."""
        )

        self.ctrl = ctrl = CSRStorage(
            fields=[
                CSRField("reset",
                         offset=5,
                         description=
                         "Write a ``1`` here to reset the `SETUP` handler.",
                         pulse=True),
            ],
            description=
            "Controls for managing how to handle ``SETUP`` transactions.")

        self.status = status = CSRStatus(
            fields=[
                CSRField(
                    "epno",
                    4,
                    description=
                    "The destination endpoint for the most recent SETUP token."
                ),
                CSRField("have",
                         description="``1`` if there is data in the FIFO."),
                CSRField("pend",
                         description="``1`` if there is an IRQ pending."),
                CSRField("is_in",
                         description="``1`` if an IN stage was detected."),
                CSRField("data",
                         description="``1`` if a DATA stage is expected."),
            ],
            description=
            "Status about the most recent ``SETUP`` transactions, and the state of the FIFO."
        )

        self.submodules.ev = ev.EventManager()
        self.ev.submodules.packet = ev.EventSourcePulse(name="ready",
                                                        description="""
                                            Indicates a ``SETUP`` packet has arrived
                                            and is waiting in the ``SETUP`` FIFO."""
                                                        )
        self.ev.submodules.reset = ev.EventSourceProcess(name="reset",
                                                         description="""
                                                        Indicates a USB ``RESET`` condition
                                                        has occurred, and the ``ADDRESS`` is now ``0``."""
                                                         )
        self.ev.finalize()
        self.trigger = trigger = self.ev.packet.trigger
        self.pending = pending = self.ev.packet.pending
        self.comb += self.ev.reset.trigger.eq(~self.usb_reset)

        self.data_recv_payload = data_recv_payload = Signal(8)
        self.data_recv_put = data_recv_put = Signal()

        # Since we must always ACK a SETUP packet, set this to 0.
        self.response = Signal()

        class SetupHandlerInner(Module):
            def __init__(self):
                self.submodules.data = buf = fifo.SyncFIFOBuffered(width=8,
                                                                   depth=10)

                # Indicates which byte of `SETUP` data we're currently on.
                data_byte = Signal(4)

                # If the incoming `SETUP` token indicates there will be
                # a DATA stage, this will be set to 1.
                self.have_data_stage = have_data_stage = Signal()

                # If the incoming `SETUP` token is an OUT packet, this
                # will be 1.
                self.is_in = is_in = Signal()

                self.empty = Signal()
                self.comb += self.empty.eq(~buf.readable)

                # Wire up the `STATUS` register
                self.comb += [
                    status.fields.have.eq(buf.readable),
                    status.fields.is_in.eq(is_in),
                    status.fields.epno.eq(epno),
                    status.fields.pend.eq(pending),
                    status.fields.data.eq(have_data_stage),
                ]

                # Wire up the "SETUP" endpoint.
                self.comb += [
                    # Set the FIFO output to be the current buffer HEAD
                    data.fields.data.eq(buf.dout),

                    # Advance the FIFO when a byte is read
                    buf.re.eq(data.we),
                    If(
                        usb_core.tok == PID.SETUP,
                        buf.din.eq(data_recv_payload),
                        buf.we.eq(data_recv_put),
                    ),

                    # Tie the trigger to the STATUS.HAVE bit
                    trigger.eq(buf.readable & usb_core.setup),
                ]

                self.sync += [
                    # The 6th and 7th bytes of SETUP data are
                    # the wLength field.  If these are nonzero,
                    # then there will be a Data stage following
                    # this Setup stage.
                    If(
                        data_recv_put,
                        If(
                            data_byte == 0,
                            epno.eq(usb_core.endp),
                            is_in.eq(data_recv_payload[7]),
                        ).Elif(
                            data_byte == 6,
                            If(
                                data_recv_payload,
                                have_data_stage.eq(1),
                            ),
                        ).Elif(
                            data_byte == 7,
                            If(
                                data_recv_payload,
                                have_data_stage.eq(1),
                            ),
                        ),
                        data_byte.eq(data_byte + 1),
                    )
                ]

        self.submodules.inner = inner = ResetInserter()(SetupHandlerInner())
        self.comb += [
            inner.reset.eq(self.reset | self.begin | ctrl.fields.reset),
            self.ev.packet.clear.eq(self.begin),
        ]

        # Expose relevant Inner signals to the top
        self.have_data_stage = inner.have_data_stage
        self.is_in = inner.is_in
        self.empty = inner.empty
Beispiel #6
0
    def __init__(self, iobuf, num_endpoints=3, depth=512):

        ptr_width = 9  # Signal(max=depth).size

        self.submodules.usb_core = usb_core = UsbTransfer(iobuf)

        self.submodules.pullup = GPIOOut(usb_core.iobuf.usb_pullup)
        self.iobuf = usb_core.iobuf

        # Output endpoints
        all_trig = []
        trig = []

        self.submodules.ev = ev.EventManager()
        for i in range(0, num_endpoints):
            exec("self.ev.oep{} = ev.EventSourcePulse()".format(i))
            t = getattr(self.ev, "oep{}".format(i)).trigger
            all_trig.append(t.eq(1))
            trig.append(t)

            exec("self.ev.iep{} = ev.EventSourcePulse()".format(i))
            t = getattr(self.ev, "iep{}".format(i)).trigger
            all_trig.append(t.eq(1))
            trig.append(t)

        self.ev.finalize()

        # eps_idx is the result of the last IN/OUT/SETUP token, and
        # therefore describes the current EP that the USB core sees.
        # The register is of the form:
        #    EEEEI
        # Where:
        #   E: The last endpoint number
        #   I: True if the current endpoint is an IN endpoint
        self.eps_idx = eps_idx = Signal(5)

        self.comb += [
            # Sic. The Cat() function places the first argument in the LSB,
            # and the second argument in the MSB.
            self.eps_idx.eq(Cat(usb_core.tok == PID.IN, usb_core.endp)),

            # self.eps_idx_in.eq(Cat(0, usb_core.endp)),
        ]

        signal_bits = num_endpoints * 2

        # Keep a copy of the control bits for each endpoint

        # Stall endpoint
        self.sta = CSRStorage(signal_bits, write_from_dev=True)

        # Data toggle bit
        self.dtb = CSRStorage(signal_bits, write_from_dev=True)

        # Endpoint is ready
        self.arm = CSRStorage(signal_bits, write_from_dev=True)

        # Wire up the USB core control bits to the currently-active
        # endpoint bit.
        self.comb += [
            usb_core.sta.eq(self.csr_bits(self.sta)[eps_idx]),
            usb_core.arm.eq(self.csr_bits(self.arm)[eps_idx]),
            usb_core.dtb.eq(~self.csr_bits(self.dtb)[eps_idx]),
            If(
                ~iobuf.usb_pullup,
                *all_trig,
            ).Else(Array(trig)[eps_idx].eq(usb_core.commit), ),
        ]

        # Output pathway
        # -----------------------
        self.specials.obuf = Memory(8, depth)
        self.specials.oport_wr = self.obuf.get_port(write_capable=True,
                                                    clock_domain="usb_12")
        self.specials.oport_rd = self.obuf.get_port(clock_domain="sys")

        optrs = []
        for i in range(0, num_endpoints):
            exec("self.optr_ep{0} = CSRStatus(ptr_width, name='optr_ep{0}')".
                 format(i))
            optrs.append(getattr(self, "optr_ep{}".format(i)).status)

        self.obuf_ptr = Signal(ptr_width)
        self.comb += [
            self.oport_wr.adr.eq(self.obuf_ptr),
            self.oport_wr.dat_w.eq(usb_core.data_recv_payload),
            self.oport_wr.we.eq(usb_core.data_recv_put),
        ]
        # On a commit, copy the current obuf_ptr to the CSR register.
        self.sync.usb_12 += [
            If(
                usb_core.commit,
                If(
                    (usb_core.tok == PID.OUT) | (usb_core.tok == PID.SETUP),
                    Array(optrs)[usb_core.endp].eq(self.obuf_ptr),
                ),
            ),
        ]

        # Set up a signal to reset EP0 when we get a SETUP packet
        self.usb_ep0_reset = Signal()
        self.update_dtb = Signal()
        self.update_ctrl = Signal()
        self.should_check_ep0 = Signal()
        #self.obuf_full = Signal()
        #self.ibuf_empty = Signal()

        # self.comb += [
        #     self.usb_ep0_reset.eq(usb_core.start & (usb_core.tok == PID.SETUP))
        # ]

        self.sync.usb_12 += [
            self.arm.we.eq(0),
            self.sta.we.eq(0),
            self.dtb.we.eq(0),
            If(usb_core.data_recv_put, self.obuf_ptr.eq(self.obuf_ptr + 1)),

            # If the EP0 needs resetting, then clear the EP0 IN and OUT bits, which
            # are stored in the lower two bits of the three control registers.
            If(
                usb_core.start,
                self.should_check_ep0.eq(1),
            ).Elif(
                self.should_check_ep0,
                self.should_check_ep0.eq(0),
                If(
                    usb_core.tok == PID.SETUP,
                    self.update_ctrl.eq(1),
                    self.update_dtb.eq(1),
                    self.arm.dat_w.eq(self.arm.storage & ~0b11),
                    self.sta.dat_w.eq(self.sta.storage & ~0b11),
                    self.dtb.dat_w.eq(self.dtb.storage & ~0b11),
                ),
            ).Elif(
                usb_core.commit,
                #self.update_ctrl.eq((self.obuf_full & ~eps_idx[0]) | (self.ibuf_empty & eps_idx[0])),
                self.update_ctrl.eq(1),
                self.update_dtb.eq(1),
                self.arm.dat_w.eq((self.arm.storage & ~(1 << eps_idx))),
                self.sta.dat_w.eq(self.sta.storage),
                self.dtb.dat_w.eq((self.dtb.storage ^ (1 << eps_idx))),
            ),
            If(
                self.update_ctrl,
                self.update_ctrl.eq(0),
                self.arm.we.eq(1),
                self.sta.we.eq(1),
            ),
            If(
                self.update_dtb,
                self.update_dtb.eq(0),
                self.dtb.we.eq(1),
            )
        ]

        #self.diff_addr = Signal(ptr_width)
        #self.comb += [
        #    self.diff_addr.eq(self.oport_rd.adr - self.oport_wr.adr),
        #    # check if there are at least 64 Bytes (== FS max packet size) left in the out buffer
        #    self.obuf_full.eq((self.diff_addr != 0) & (self.diff_addr <= 64)),
        #    #self.obuf_full.eq(  (self.diff_addr[7::] == 0) &
        #    #                    (self.diff_addr[0:7] != 0)),
        #]

        # Input pathway
        # -----------------------
        self.specials.ibuf = Memory(8, depth)
        self.specials.iport_wr = self.ibuf.get_port(write_capable=True,
                                                    clock_domain="sys")
        self.specials.iport_rd = self.ibuf.get_port(clock_domain="usb_12")

        #for i in range(0, num_endpoints):
        #    exec("self.submodules.iptr_ep{0} = CSRStorage(ptr_width, name='iptr_ep{0}')".format(i))
        #    iptrs.append(getattr(self, "iptr_ep{}".format(i)).storage)
        #
        #    exec("self.submodules.ilen_ep{0} = CSRStorage(ptr_width, name='ilen_ep{0}')".format(i))
        #    ilens.append(getattr(self, "ilen_ep{}".format(i)).storage)
        assert num_endpoints == 3
        self.iptr_ep0 = CSRStorage(ptr_width)
        self.ilen_ep0 = CSRStorage(ptr_width)
        self.iptr_ep1 = CSRStorage(ptr_width)
        self.ilen_ep1 = CSRStorage(ptr_width)
        self.iptr_ep2 = CSRStorage(ptr_width)
        self.ilen_ep2 = CSRStorage(ptr_width)
        iptrs = [
            self.iptr_ep0.storage, self.iptr_ep1.storage, self.iptr_ep2.storage
        ]
        ilens = [
            self.ilen_ep0.storage, self.ilen_ep1.storage, self.ilen_ep2.storage
        ]

        self.ibuf_ptr = Signal(ptr_width)
        self.comb += [
            self.iport_rd.adr.eq(self.ibuf_ptr),
            usb_core.data_send_payload.eq(self.iport_rd.dat_r),
            #self.iport_rd.re.eq(),
        ]
        # On a transfer start, copy the CSR register into ibuf_ptr
        self.sync.usb_12 += [
            If(
                usb_core.start,
                self.ibuf_ptr.eq(Array(iptrs)[usb_core.endp]),
            ),
        ]
        self.sync.usb_12 += [
            If(usb_core.data_send_get, self.ibuf_ptr.eq(self.ibuf_ptr + 1)),
        ]
        self.comb += [
            usb_core.data_send_have.eq(
                self.ibuf_ptr != Array(ilens)[usb_core.endp]),
        ]
Beispiel #7
0
    def __init__(self, iobuf):
        self.submodules.ev = ev.EventManager()
        self.ev.submodules.rx = ev.EventSourcePulse()

        # ---------------------
        # RX side
        # ---------------------
        self.submodules.rx = rx = RxPipeline()
        self.byte_count = CSRStatus(8)

        obuf = fifo.AsyncFIFOBuffered(width=8, depth=128)
        self.submodules.obuf = ClockDomainsRenamer({
            "write": "usb_12",
            "read": "sys"
        })(obuf)

        # USB side (writing)
        self.comb += [
            self.obuf.din.eq(self.rx.o_data_payload),
            self.obuf.we.eq(self.rx.o_data_strobe),
        ]
        self.sync.usb_12 += [
            self.ev.rx.trigger.eq(self.rx.o_pkt_end),
            If(self.rx.o_data_strobe,
               self.byte_count.status.eq(self.byte_count.status + 1))
        ]

        # System side (reading)
        self.obuf_head = CSR(8)
        self.obuf_empty = CSRStatus(1)
        self.comb += [
            self.obuf_head.w.eq(self.obuf.dout),
            self.obuf.re.eq(self.obuf_head.re),
            self.obuf_empty.status.eq(~self.obuf.readable),
        ]

        # ---------------------
        # TX side
        # ---------------------
        self.submodules.tx = tx = TxPipeline()

        ibuf = fifo.AsyncFIFOBuffered(width=8, depth=128)
        self.submodules.ibuf = ClockDomainsRenamer({
            "write": "sys",
            "read": "usb_12"
        })(ibuf)

        # System side (writing)
        self.arm = CSRStorage(1)
        self.ibuf_head = CSR(8)
        self.ibuf_empty = CSRStatus(1)
        self.comb += [
            self.ibuf.din.eq(self.ibuf_head.r),
            self.ibuf.we.eq(self.ibuf_head.re),
            self.ibuf_empty.status.eq(~self.ibuf.readable & ~tx.o_oe),
        ]

        # USB side (reading)
        self.comb += [
            tx.i_data_payload.eq(self.ibuf.dout),
            self.ibuf.re.eq(tx.o_data_strobe & self.arm.storage),
        ]
        self.sync.usb_12 += [
            tx.i_oe.eq(self.ibuf.readable & self.arm.storage),
        ]

        # ----------------------
        # USB 48MHz bit strobe
        # ----------------------
        self.comb += [
            tx.i_bit_strobe.eq(rx.o_bit_strobe),
        ]

        # ----------------------
        # Tristate
        # ----------------------
        self.submodules.iobuf = iobuf
        self.comb += [
            rx.i_usbp.eq(iobuf.usb_p_rx),
            rx.i_usbn.eq(iobuf.usb_n_rx),
            iobuf.usb_tx_en.eq(tx.o_oe),
            iobuf.usb_p_tx.eq(tx.o_usbp),
            iobuf.usb_n_tx.eq(tx.o_usbn),
        ]
        self.submodules.pullup = GPIOOut(iobuf.usb_pullup)