Exemplo n.º 1
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
Exemplo n.º 2
0
    def check(self, m: Module):
        with m.If(self.instr.matches(JSR_EXT)):
            self.assert_cycles(m, 9)
            addr_hi = self.assert_cycle_signals(m,
                                                1,
                                                address=self.data.pre_pc + 1,
                                                vma=1,
                                                rw=1,
                                                ba=0)
            addr_lo = self.assert_cycle_signals(m,
                                                2,
                                                address=self.data.pre_pc + 2,
                                                vma=1,
                                                rw=1,
                                                ba=0)
            _ = self.assert_cycle_signals(m,
                                          3,
                                          address=LCat(addr_hi, addr_lo),
                                          vma=1,
                                          rw=1,
                                          ba=0)
            retaddr_lo = self.assert_cycle_signals(m,
                                                   4,
                                                   address=self.data.pre_sp,
                                                   vma=1,
                                                   rw=0,
                                                   ba=0)
            retaddr_hi = self.assert_cycle_signals(m,
                                                   5,
                                                   address=self.data.pre_sp -
                                                   1,
                                                   vma=1,
                                                   rw=0,
                                                   ba=0)
            self.assert_cycle_signals(m, 6, vma=0, ba=0)
            self.assert_cycle_signals(m, 7, vma=0, ba=0)

            # I am not convinced the datasheet is correct for this cycle.
            # It claims there is a read of the pc+2 here.
            self.assert_cycle_signals(m, 8, vma=0, ba=0)

            self.assert_registers(m,
                                  SP=self.data.pre_sp - 2,
                                  PC=LCat(addr_hi, addr_lo))
            m.d.comb += Assert(
                LCat(retaddr_hi, retaddr_lo) == (self.data.pre_pc + 3)[:16])

        with m.Else():
            self.assert_cycles(m, 8)
            offset = self.assert_cycle_signals(m,
                                               1,
                                               address=self.data.pre_pc + 1,
                                               vma=1,
                                               rw=1,
                                               ba=0)
            self.assert_cycle_signals(m, 2, vma=0, ba=0)
            retaddr_lo = self.assert_cycle_signals(m,
                                                   3,
                                                   address=self.data.pre_sp,
                                                   vma=1,
                                                   rw=0,
                                                   ba=0)
            retaddr_hi = self.assert_cycle_signals(m,
                                                   4,
                                                   address=self.data.pre_sp -
                                                   1,
                                                   vma=1,
                                                   rw=0,
                                                   ba=0)
            self.assert_cycle_signals(m, 5, vma=0, ba=0)
            self.assert_cycle_signals(m, 6, vma=0, ba=0)
            self.assert_cycle_signals(m, 7, vma=0, ba=0)

            self.assert_registers(m,
                                  SP=self.data.pre_sp - 2,
                                  PC=self.data.pre_x + offset)
            m.d.comb += Assert(
                LCat(retaddr_hi, retaddr_lo) == (self.data.pre_pc + 2)[:16])

        self.assert_flags(m)
Exemplo n.º 3
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
Exemplo n.º 4
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        m.d.sync += self.PSW.eq(self._psw)
        m.d.comb += self._psw.eq(self.PSW)

        with m.Switch(self.oper):
            with m.Case(Operation.NOP):
                if self.verification is Operation.NOP:
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self._psw.N == self.PSW.N),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == self.PSW.Z),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.ADC):
                low = Cat(self.result[:4], self._psw.H)
                high = Cat(self.result[4:], self._psw.C)

                m.d.comb += [
                    low.eq(self.inputa[:4] + self.inputb[:4] + self.PSW.C),
                    high.eq(self.inputa[4:] + self.inputb[4:] + self._psw.H),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                    self._psw.V.eq(self.result[7] != self._psw.C),
                ]
                if self.verification is Operation.ADC:
                    r = Signal(8)
                    f = Signal(9)
                    h = Signal(5)
                    m.d.comb += [
                        r.eq(self.inputa.as_signed() +
                             self.inputb.as_signed() + self.PSW.C),
                        f.eq(self.inputa + self.inputb + self.PSW.C),
                        h.eq(self.inputa[:4] + self.inputb[:4] + self.PSW.C),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self.result == f[:8]),
                            Assert(self._psw.N == f[7]),
                            Assert(self._psw.V == (f[7] ^ f[8])),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == h[4]),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(f[:8].bool())),
                            Assert(self._psw.C == f[8]),
                        ]

            with m.Case(Operation.SBC):
                low = Cat(self.result[:4], self._psw.H)
                high = Cat(self.result[4:], self._psw.C)

                m.d.comb += [
                    low.eq(self.inputa[:4] - self.inputb[:4] - self.PSW.C),
                    high.eq(self.inputa[4:] - self.inputb[4:] - self._psw.H),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                    self._psw.V.eq(self.result[7] != self._psw.C),
                ]
                if self.verification is Operation.SBC:
                    r = Signal(8)
                    f = Signal(9)
                    h = Signal(5)
                    m.d.comb += [
                        r.eq(self.inputa.as_signed() -
                             self.inputb.as_signed() - self.PSW.C),
                        f.eq(self.inputa - self.inputb - self.PSW.C),
                        h.eq(self.inputa[:4] - self.inputb[:4] - self.PSW.C),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self.result == f[:8]),
                            Assert(self._psw.N == f[7]),
                            Assert(self._psw.V == (f[7] ^ f[8])),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == h[4]),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(f[:8].bool())),
                            Assert(self._psw.C == f[8]),
                        ]

            with m.Case(Operation.CMP):
                full = Cat(self.result, self._psw.C)

                m.d.comb += [
                    full.eq(self.inputa.as_signed() - self.inputb.as_signed()),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                    self._psw.V.eq(self.result[7] != self._psw.C),
                ]
                if self.verification is Operation.CMP:
                    r = Signal(9)
                    m.d.comb += r.eq(self.inputa.as_signed() -
                                     self.inputb.as_signed())
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r[:8]),
                            Assert(self._psw.N == r[7]),
                            Assert(self._psw.V == (r[7] ^ r[8])),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r[:8].bool())),
                            Assert(self._psw.C == r[8]),
                        ]

            with m.Case(Operation.AND):
                m.d.comb += [
                    self.result.eq(self.inputa & self.inputb),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.AND:
                    r = Signal(8)
                    m.d.comb += r.eq(self.inputa & self.inputb)
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == r[7]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.OOR):
                m.d.comb += [
                    self.result.eq(self.inputa | self.inputb),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.OOR:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa | self.inputb),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == r[7]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.EOR):
                m.d.comb += [
                    self.result.eq(self.inputa ^ self.inputb),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.EOR:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa ^ self.inputb),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == r[7]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.INC):
                m.d.comb += [
                    self.result.eq(self.inputa + 1),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.INC:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa + 1),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == r[7]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.DEC):
                m.d.comb += [
                    self.result.eq(self.inputa - 1),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.DEC:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa - 1),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == r[7]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.ASL):
                m.d.comb += [
                    Cat(self.result,
                        self._psw.C).eq(Cat(Const(0), self.inputa)),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.ASL:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa * 2),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == self.inputa[6]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.inputa[7]),
                        ]

            with m.Case(Operation.LSR):
                m.d.comb += [
                    Cat(self._psw.C,
                        self.result).eq(Cat(self.inputa, Const(0))),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.LSR:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa // 2),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == 0),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.inputa[0]),
                        ]

            with m.Case(Operation.ROL):
                m.d.comb += [
                    Cat(self.result,
                        self._psw.C).eq(Cat(self.PSW.C, self.inputa)),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.ROL:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa * 2 + self.PSW.C),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == self.inputa[6]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.inputa[7]),
                        ]

            with m.Case(Operation.ROR):
                m.d.comb += [
                    Cat(self._psw.C,
                        self.result).eq(Cat(self.inputa, self.PSW.C)),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.ROR:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa // 2 + Cat(Signal(7), self.PSW.C)),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == self.PSW.C),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r.bool())),
                            Assert(self._psw.C == self.inputa[0]),
                        ]

            with m.Case(Operation.XCN):
                m.d.comb += [
                    self.result.eq(Cat(self.inputa[4:], self.inputa[:4])),
                    self._psw.N.eq(self.result.as_signed() < 0),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.XCN:
                    r = Signal(8)
                    m.d.comb += [
                        r.eq(self.inputa * 16 + self.inputa // 16),
                    ]
                    with m.If(~Initial()):
                        m.d.comb += [
                            Assert(self.result == r),
                            Assert(self._psw.N == self.inputa[3]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(self.inputa.bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]

            with m.Case(Operation.DAA):
                temp = Signal().like(self.inputa)
                with m.If(self.PSW.C | (self.inputa > 0x99)):
                    m.d.comb += self._psw.C.eq(1)
                    m.d.comb += temp.eq(self.inputa + 0x60)
                with m.Else():
                    m.d.comb += temp.eq(self.inputa)

                with m.If(self.PSW.H | (temp[:4] > 0x09)):
                    m.d.comb += self.result.eq(temp + 0x06)

                m.d.comb += [
                    self._psw.N.eq(self.result & 0x80),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.DAA:
                    with m.If(~Initial()):
                        m.d.comb += [Assert(False)]

            with m.Case(Operation.DAS):
                temp = Signal().like(self.inputa)
                with m.If(~self.PSW.C | (self.inputa > 0x99)):
                    m.d.comb += self._psw.C.eq(0)
                    m.d.comb += temp.eq(self.inputa - 0x60)
                with m.Else():
                    m.d.comb += temp.eq(self.inputa)

                with m.If(~self.PSW.H | (temp[:4] > 0x09)):
                    m.d.comb += self.result.eq(temp - 0x06)

                m.d.comb += [
                    self._psw.N.eq(self.result & 0x80),
                    self._psw.Z.eq(self.result == 0),
                ]
                if self.verification is Operation.DAS:
                    with m.If(~Initial()):
                        m.d.comb += [Assert(False)]

            # could be optimized with shift to right
            with m.Case(Operation.MUL):
                with m.Switch(self.count):
                    for i in range(0, 8):
                        with m.Case(i):
                            prod = self.inputa * self.inputb[i]
                            if i == 0:
                                prod = Cat(prod[0:7], ~prod[7], Const(1))
                            elif i == 7:
                                prod = Cat(~prod[0:7], prod[7], Const(1))
                            else:
                                prod = Cat(prod[0:7], ~prod[7])
                            m.d.sync += self.partial.eq(self.partial +
                                                        (prod << i))
                            m.d.sync += self.count.eq(i + 1)
                    with m.Case(8):
                        m.d.sync += self.partial_hi.eq(self.partial_lo)
                        m.d.sync += self.count.eq(9)
                        m.d.comb += [
                            self.result.eq(self.partial_hi),
                            self._psw.N.eq(self.partial_hi.as_signed() < 0),
                            self._psw.Z.eq(self.partial_hi == 0),
                        ]
                    with m.Case(9):
                        m.d.sync += self.partial.eq(0)
                        m.d.sync += self.count.eq(0)
                        m.d.comb += [
                            self.result.eq(self.partial_hi),
                        ]
                if self.verification is Operation.MUL:
                    r = Signal(16)
                    m.d.comb += [
                        r.eq(self.inputa.as_signed() *
                             self.inputb.as_signed()),
                        Cover(self.count == 9),
                    ]
                    with m.If(self.count == 9):
                        m.d.comb += [
                            Assert(Past(self.result) == r[8:16]),
                            Assert(self.result == r[0:8]),
                            Assert(self._psw.N == r[15]),
                            Assert(self._psw.V == self.PSW.V),
                            Assert(self._psw.P == self.PSW.P),
                            Assert(self._psw.B == self.PSW.B),
                            Assert(self._psw.H == self.PSW.H),
                            Assert(self._psw.I == self.PSW.I),
                            Assert(self._psw.Z == ~(r[8:16].bool())),
                            Assert(self._psw.C == self.PSW.C),
                        ]
                    with m.If(~Initial() & (self.count == 0)):
                        m.d.comb += [
                            Assert(self.partial == 0),
                            Assert((Past(self.count) == 0)
                                   | (Past(self.count) == 9)),
                        ]
                    with m.If(~Initial() & (self.count != 0)):
                        m.d.comb += [
                            Assert(self.count == Past(self.count) + 1),
                            Assume(self.inputa == Past(self.inputa)),
                            Assume(self.inputb == Past(self.inputb)),
                        ]

            with m.Case(Operation.DIV):
                over = Signal(reset=0)
                with m.Switch(self.count):
                    with m.Case(0):
                        m.d.sync += self.partial_hi.eq(self.inputa)  # Y
                        m.d.sync += self.count.eq(1)

                    with m.Case(1):
                        m.d.sync += self.partial_lo.eq(self.inputa)  # A
                        m.d.sync += self.count.eq(2)
                        m.d.comb += self._psw.H.eq(
                            Mux(self.partial_hi[0:4] >= self.inputb[0:4], 1,
                                0))

                    for i in range(2, 11):
                        with m.Case(i):
                            tmp1_w = Cat(self.partial << 1, over)
                            tmp1_x = Signal(17)
                            tmp1_y = Signal(17)
                            tmp1_z = Signal(17)
                            tmp2 = self.inputb << 9

                            m.d.comb += tmp1_x.eq(tmp1_w)
                            with m.If(tmp1_w & 0x20000):
                                m.d.comb += tmp1_x.eq((tmp1_w & 0x1FFFF) | 1)

                            m.d.comb += tmp1_y.eq(tmp1_x)
                            with m.If(tmp1_x >= tmp2):
                                m.d.comb += tmp1_y.eq(tmp1_x ^ 1)

                            m.d.comb += tmp1_z.eq(tmp1_y)
                            with m.If(tmp1_y & 1):
                                m.d.comb += tmp1_z.eq((tmp1_y - tmp2)
                                                      & 0x1FFFF)

                            m.d.sync += Cat(self.partial, over).eq(tmp1_z)

                            m.d.sync += self.count.eq(i + 1)

                    with m.Case(11):
                        m.d.sync += self.count.eq(12)
                        m.d.comb += [
                            self.result.eq(
                                (Cat(self.partial, over) >> 9)),  # Y %
                        ]

                    with m.Case(12):
                        m.d.sync += self.partial.eq(0)
                        m.d.sync += over.eq(0)
                        m.d.sync += self.count.eq(0)
                        m.d.comb += [
                            self.result.eq(self.partial_lo),  # A /
                            self._psw.N.eq(self.partial_lo.as_signed() < 0),
                            self._psw.V.eq(over),
                            self._psw.Z.eq(self.partial_lo == 0),
                        ]

                if self.verification is Operation.DIV:
                    m.d.comb += [
                        Cover(self.count == 12),
                    ]
                    with m.If(self.count == 12):
                        m.d.comb += [Assert(False)]

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

        wbuffer_layout = [("addr", 32), ("data", 32), ("sel", 4)]

        wbuffer_din = Record(wbuffer_layout)
        wbuffer_dout = Record(wbuffer_layout)

        dcache = m.submodules.dcache = Cache(nlines=self.nlines,
                                             nwords=self.nwords,
                                             nways=self.nways,
                                             start_addr=self.start_addr,
                                             end_addr=self.end_addr,
                                             enable_write=True)
        arbiter = m.submodules.arbiter = Arbiter()
        wbuffer = m.submodules.wbuffer = SyncFIFOBuffered(
            width=len(wbuffer_din), depth=self.nwords)

        wbuffer_port = arbiter.add_port(priority=0)
        cache_port = arbiter.add_port(priority=1)
        bare_port = arbiter.add_port(priority=2)

        x_use_cache = Signal()
        m_use_cache = Signal()
        m_data_w = Signal(32)
        m_byte_sel = Signal(4)

        bits_range = log2_int(self.end_addr - self.start_addr, need_pow2=False)
        m.d.comb += x_use_cache.eq(
            (self.x_addr[bits_range:] == (self.start_addr >> bits_range)))

        with m.If(~self.x_stall):
            m.d.sync += [
                m_use_cache.eq(x_use_cache),
                m_data_w.eq(self.x_data_w),
                m_byte_sel.eq(self.x_byte_sel)
            ]
        m.d.comb += arbiter.bus.connect(self.dport)

        # --------------------------------------------------
        # write buffer IO
        m.d.comb += [
            # input
            wbuffer.w_data.eq(wbuffer_din),
            wbuffer.w_en.eq(x_use_cache & self.x_store & self.x_valid
                            & ~self.x_stall),
            wbuffer_din.addr.eq(self.x_addr),
            wbuffer_din.data.eq(self.x_data_w),
            wbuffer_din.sel.eq(self.x_byte_sel),
            # output
            wbuffer_dout.eq(wbuffer.r_data),
        ]

        # drive the arbiter port
        with m.If(wbuffer_port.cyc):
            with m.If(wbuffer_port.ack | wbuffer_port.err):
                m.d.comb += wbuffer.r_en.eq(1)
                m.d.sync += wbuffer_port.stb.eq(0)
                with m.If(wbuffer.level == 1):  # Buffer is empty
                    m.d.sync += [wbuffer_port.cyc.eq(0), wbuffer_port.we.eq(0)]
            with m.Elif(~wbuffer_port.stb):
                m.d.sync += [
                    wbuffer_port.stb.eq(1),
                    wbuffer_port.addr.eq(wbuffer_dout.addr),
                    wbuffer_port.dat_w.eq(wbuffer_dout.data),
                    wbuffer_port.sel.eq(wbuffer_dout.sel)
                ]
        with m.Elif(wbuffer.r_rdy):
            m.d.sync += [
                wbuffer_port.cyc.eq(1),
                wbuffer_port.stb.eq(1),
                wbuffer_port.we.eq(1),
                wbuffer_port.addr.eq(wbuffer_dout.addr),
                wbuffer_port.dat_w.eq(wbuffer_dout.data),
                wbuffer_port.sel.eq(wbuffer_dout.sel)
            ]
            m.d.comb += wbuffer.r_en.eq(0)
        m.d.comb += [
            wbuffer_port.cti.eq(CycleType.CLASSIC),
            wbuffer_port.bte.eq(0)
        ]

        # --------------------------------------------------
        # connect IO: cache
        m.d.comb += [
            dcache.s1_address.eq(self.x_addr),
            dcache.s1_flush.eq(0),
            dcache.s1_valid.eq(self.x_valid),
            dcache.s1_stall.eq(self.x_stall),
            dcache.s2_address.eq(self.m_addr),
            dcache.s2_evict.eq(0),  # Evict is not used. Remove maybe?
            dcache.s2_valid.eq(self.m_valid),
            dcache.s2_re.eq(self.m_load),
            dcache.s2_wdata.eq(m_data_w),
            dcache.s2_sel.eq(m_byte_sel),
            dcache.s2_we.eq(self.m_store)
        ]

        # connect cache to arbiter
        m.d.comb += [
            cache_port.addr.eq(dcache.bus_addr),
            cache_port.dat_w.eq(0),
            cache_port.sel.eq(0),
            cache_port.we.eq(0),
            cache_port.cyc.eq(dcache.bus_valid),
            cache_port.stb.eq(dcache.bus_valid),
            cache_port.cti.eq(
                Mux(dcache.bus_last, CycleType.END, CycleType.INCREMENT)),
            cache_port.bte.eq(log2_int(self.nwords) - 1),
            dcache.bus_data.eq(cache_port.dat_r),
            dcache.bus_ack.eq(cache_port.ack),
            dcache.bus_err.eq(cache_port.err)
        ]

        # --------------------------------------------------
        # bare port
        rdata = Signal.like(bare_port.dat_r)
        op = Signal()

        m.d.comb += op.eq(self.x_load | self.x_store)

        # transaction logic
        with m.If(bare_port.cyc):
            with m.If(bare_port.ack | bare_port.err | ~self.m_valid):
                m.d.sync += [
                    rdata.eq(bare_port.dat_r),
                    bare_port.we.eq(0),
                    bare_port.cyc.eq(0),
                    bare_port.stb.eq(0)
                ]
        with m.Elif(op & self.x_valid & ~self.x_stall & ~x_use_cache):
            m.d.sync += [
                bare_port.addr.eq(self.x_addr),
                bare_port.dat_w.eq(self.x_data_w),
                bare_port.sel.eq(self.x_byte_sel),
                bare_port.we.eq(self.x_store),
                bare_port.cyc.eq(1),
                bare_port.stb.eq(1)
            ]
        m.d.comb += [bare_port.cti.eq(CycleType.CLASSIC), bare_port.bte.eq(0)]

        # --------------------------------------------------
        # extra logic
        with m.If(self.x_fence_i):
            m.d.comb += self.x_busy.eq(wbuffer.r_rdy)
        with m.Elif(x_use_cache):
            m.d.comb += self.x_busy.eq(self.x_store & ~wbuffer.w_rdy)
        with m.Else():
            m.d.comb += self.x_busy.eq(bare_port.cyc)

        with m.If(m_use_cache):
            m.d.comb += [
                self.m_busy.eq(dcache.s2_re & dcache.s2_miss),
                self.m_load_data.eq(dcache.s2_rdata)
            ]
        with m.Elif(self.m_load_error | self.m_store_error):
            m.d.comb += [self.m_busy.eq(0), self.m_load_data.eq(0)]
        with m.Else():
            m.d.comb += [
                self.m_busy.eq(bare_port.cyc),
                self.m_load_data.eq(rdata)
            ]

        # --------------------------------------------------
        # exceptions
        with m.If(self.dport.cyc & self.dport.err):
            m.d.sync += [
                self.m_load_error.eq(~self.dport.we),
                self.m_store_error.eq(self.dport.we),
                self.m_badaddr.eq(self.dport.addr)
            ]
        with m.Elif(~self.m_stall):
            m.d.sync += [self.m_load_error.eq(0), self.m_store_error.eq(0)]

        return m
Exemplo n.º 6
0
    if args.instr is not None:
        instr = getattr(modules["instruction.implemented"], args.instr.split(".")[0])
        instr = getattr(instr, args.instr.split(".")[1])
        if instr not in implemented.implemented:
            raise AttributeError()

    m = Module()
    m.submodules.core = core = Core(instr)

    if instr is not None:
        time = Signal(6, reset_less=True)
        m.d.sync += time.eq(time + 1)

        with m.If(Initial()):
            m.d.sync += Assume(ResetSignal())
        with m.Else():
            m.d.sync += Assume(~ResetSignal())

        # A time slot delayed because PC and addr need to sync
        with m.If(time == 2):
            m.d.sync += Assume(~core.snapshot.taken)
        with m.If(time == 3):
            m.d.sync += Cover(core.snapshot.taken)
            m.d.sync += Assume(core.snapshot.taken)
        m.d.sync += Cover(Fell(core.snapshot.taken))

        main_runner(
            parser, args, m, ports=core.ports() + [ClockSignal(), ResetSignal()]
        )

    else:
Exemplo n.º 7
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

        m.d.comb += [
            self.data_requested.eq(data_requested),
        ]

        # 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)
        ]

        m.d.usb += [
            self.data_packet_starting.eq(0),
        ]

        m.d.comb += [
            self.byte_advance.eq(out_stream.ready),
        ]

        #
        # 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.d.usb += self.data_packet_starting.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
Exemplo n.º 8
0
Arquivo: reset.py Projeto: ymz000/luna
    def elaborate(self, platform):
        m = Module()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                # Switch to high speed.
                m.d.usb += [
                    timer.eq(0),
                    line_state_time.eq(0),
                    self.current_speed.eq(USBSpeed.HIGH),
                    self.operating_mode.eq(UTMIOperatingMode.NORMAL),
                    self.termination_select.eq(UTMITerminationSelect.HS_NORMAL)
                ]

                m.next = 'HS_NON_RESET'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        return m
Exemplo n.º 9
0
    def elaborate(self, platform):
        m = Module()
        # add 1 MHZ clock domain
        cntr = Signal(range(self.divider))
        # pos
        max_bits = (self.max_steps << 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][BIT_SHIFT]),
                self.totalsteps[motor].eq(cntrs[motor *
                                                self.order] >> (BIT_SHIFT + 1))
            ]
        # 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'):
                m.d.sync += self.busy.eq(0)
                with m.If(self.start):
                    for motor in range(self.motors):
                        coef0 = motor * self.order
                        m.d.sync += [
                            cntrs[coef0 + 2].eq(0), cntrs[coef0 + 1].eq(0),
                            cntrs[coef0].eq(0), counter_d[motor].eq(0)
                        ]
                    m.d.sync += self.busy.eq(1)
                    m.next = 'RUNNING'
            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):
                        idx = motor * self.order
                        op3 = 3 * 2 * self.coeff[idx + 2] + cntrs[idx + 2]
                        op2 = (cntrs[idx + 2] + 2 * self.coeff[idx + 1] +
                               cntrs[idx + 1])
                        op1 = (self.coeff[idx + 2] + self.coeff[idx + 1] +
                               self.coeff[idx] + cntrs[idx + 2] +
                               cntrs[idx + 1] + cntrs[idx])
                        m.d.sync += [
                            cntrs[idx + 2].eq(op3), cntrs[idx + 1].eq(op2),
                            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
Exemplo n.º 10
0
    def elaborate(self, platform):
        m = Module()

        # Baud generator.
        baud_counter = Signal(range(0, self.divisor))

        # Tx shift register; holds our data, a start, and a stop bit.
        bits_per_frame = len(self.data) + 2
        data_shift     = Signal(bits_per_frame)
        bits_to_send   = Signal(range(0, len(data_shift)))

        # Create an internal signal equal to our input data framed with a start/stop bit.
        framed_data_in = Cat(self.START_BIT, self.data, self.STOP_BIT)

        # Idle our strobes low unless asserted.
        m.d.sync += [
            self.accepted  .eq(0)
        ]

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

            # IDLE: transmitter is waiting for input
            with m.State("IDLE"):
                m.d.comb += self.tx.eq(1)  # idle high

                # Once we get a send request, fill in our shift register, and start shifting.
                with m.If(self.send):
                    m.d.sync += [
                        baud_counter  .eq(self.divisor   - 1),
                        bits_to_send  .eq(len(data_shift) - 1),
                        data_shift    .eq(framed_data_in),
                        self.accepted .eq(1)
                    ]

                    m.next = "TRANSMIT"


            # TRANSMIT: actively shift out start/data/stop
            with m.State("TRANSMIT"):
                m.d.comb += self.tx       .eq(data_shift[0])
                m.d.sync += baud_counter  .eq(baud_counter - 1)

                # If we've finished a bit period...
                with m.If(baud_counter == 0):
                    m.d.sync += baud_counter.eq(self.divisor - 1)

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

                    # Otherwise, complete the frame.
                    with m.Else():

                        # If we still have data to send, move to the next byte...
                        with m.If(self.send):
                            m.d.sync += [
                                bits_to_send  .eq(bits_per_frame - 1),
                                data_shift    .eq(framed_data_in),
                                self.accepted .eq(1)
                            ]

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


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

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

        ways     = Array(Record(way_layout) for _way in range(self.nways))
        fill_cnt = Signal.like(self.s1_address.offset)
        # set the LRU
        if self.nways == 1:
            lru = Const(0)  # self.nlines
        else:
            lru = Signal(self.nlines)
            with m.If(self.bus_valid & self.bus_ack & self.bus_last):  # err ^ ack == 1
                _lru = lru.bit_select(self.s2_address.line, 1)
                m.d.sync += lru.bit_select(self.s2_address.line, 1).eq(~_lru)

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

        m.d.comb += self.s2_miss.eq(way_hit.n)
        if self.enable_write:
            m.d.comb += ways[way_hit.o].sel_we.eq(self.s2_we & self.s2_valid)

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

        with m.FSM():
            with m.State('READ'):
                with m.If(self.s2_re & self.s2_miss & self.s2_valid):
                    m.d.sync += [
                        self.bus_addr.eq(self.s2_address),  # WARNING extra_bits
                        self.bus_valid.eq(1),
                        fill_cnt.eq(self.s2_address.offset - 1)
                    ]
                    m.next = 'REFILL'
            with m.State('REFILL'):
                m.d.comb += self.bus_last.eq(fill_cnt == self.bus_addr.offset)
                with m.If(self.bus_ack):
                    m.d.sync += self.bus_addr.offset.eq(self.bus_addr.offset + 1)
                with m.If(self.bus_ack & self.bus_last | self.bus_err):
                    m.d.sync += self.bus_valid.eq(0)
                with m.If(~self.bus_valid | self.s1_flush):
                    # in case of flush, abort ongoing refill.
                    m.next = 'READ'
                    m.d.sync += self.bus_valid.eq(0)

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

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

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

            data_m  = Memory(width=len(way.data), depth=self.nlines)
            data_rp = data_m.read_port()
            data_wp = data_m.write_port(granularity=32)
            m.submodules += data_rp, data_wp

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

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

                data_rp.addr.eq(Mux(self.s1_stall, self.s2_address.line, self.s1_address.line)),

                way.data.eq(data_rp.data),
                way.tag.eq(tag_rp.data),
                way.valid.eq(valid.bit_select(self.s2_address.line, 1))
            ]

            # update cache: CPU or Refill
            if self.enable_write:
                update_addr = Signal(len(data_wp.addr))
                update_data = Signal(len(data_wp.data))
                update_we   = Signal(len(data_wp.en))
                aux_wdata   = Signal(32)

                with m.If(self.bus_valid):
                    m.d.comb += [
                        update_addr.eq(self.bus_addr.line),
                        update_data.eq(Repl(self.bus_data, self.nwords)),
                        update_we.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack),
                    ]
                with m.Else():
                    m.d.comb += [
                        update_addr.eq(self.s2_address.line),
                        update_data.eq(Repl(aux_wdata, self.nwords)),
                        update_we.bit_select(self.s2_address.offset, 1).eq(way.sel_we & ~self.s2_miss)
                    ]
                m.d.comb += [
                    aux_wdata.eq(Cat(
                        Mux(self.s2_sel[0], self.s2_wdata.word_select(0, 8), self.s2_rdata.word_select(0, 8)),
                        Mux(self.s2_sel[1], self.s2_wdata.word_select(1, 8), self.s2_rdata.word_select(1, 8)),
                        Mux(self.s2_sel[2], self.s2_wdata.word_select(2, 8), self.s2_rdata.word_select(2, 8)),
                        Mux(self.s2_sel[3], self.s2_wdata.word_select(3, 8), self.s2_rdata.word_select(3, 8))
                    )),
                    #
                    data_wp.addr.eq(update_addr),
                    data_wp.data.eq(update_data),
                    data_wp.en.eq(update_we),
                ]
            else:
                m.d.comb += [
                    data_wp.addr.eq(self.bus_addr.line),
                    data_wp.data.eq(Repl(self.bus_data, self.nwords)),
                    data_wp.en.bit_select(self.bus_addr.offset, 1).eq(way.sel_lru & self.bus_ack),
                ]

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

        clk_60MHz = platform.request(platform.default_clk)

        # Drive the sync clock domain with our main clock.
        m.domains.sync = ClockDomain()
        m.d.comb += ClockSignal().eq(clk_60MHz)

        # Create a set of registers, and expose them over SPI.
        board_spi = platform.request("debug_spi")
        spi_registers = SPIRegisterInterface(default_read_value=-1)
        m.submodules.spi_registers = spi_registers

        # Identify ourselves as the SPI flash bridge.
        spi_registers.add_read_only_register(REGISTER_ID, read=0x53504946)

        #
        # For now, keep resources on our right-side I/O network used.
        #
        platform.request("target_phy")

        #
        # SPI flash passthrough connections.
        #
        flash_sdo = Signal()

        spi_flash_bus = platform.request('spi_flash')
        spi_flash_passthrough = ECP5ConfigurationFlashInterface(
            bus=spi_flash_bus)

        m.submodules += spi_flash_passthrough
        m.d.comb += [
            spi_flash_passthrough.sck.eq(board_spi.sck),
            spi_flash_passthrough.sdi.eq(board_spi.sdi),
            flash_sdo.eq(spi_flash_passthrough.sdo),
        ]

        #
        # Structural connections.
        #
        sck = Signal()
        sdi = Signal()
        cs = Signal()
        gateware_sdo = Signal()

        #
        # Synchronize each of our I/O SPI signals, where necessary.
        #
        m.submodules += FFSynchronizer(board_spi.sck, sck)
        m.submodules += FFSynchronizer(board_spi.sdi, sdi)
        m.submodules += FFSynchronizer(board_spi.cs, cs)

        # Select the passthrough or gateware SPI based on our chip-select values.
        with m.If(spi_registers.cs):
            m.d.comb += board_spi.sdo.eq(gateware_sdo)
        with m.Else():
            m.d.comb += board_spi.sdo.eq(flash_sdo)

        # Connect our register interface to our board SPI.
        m.d.comb += [
            spi_registers.sck.eq(sck),
            spi_registers.sdi.eq(sdi),
            gateware_sdo.eq(spi_registers.sdo),
            spi_registers.cs.eq(cs)
        ]

        return m
Exemplo n.º 13
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.
        # Since each buffer will be used for every other transaction, and our PID toggle flips every other transcation,
        # we'll identify which buffer we're targeting by the current PID toggle.
        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.data_pid[0]
        read_buffer_number  = ~self.data_pid[0]

        # 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"strem_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.data_pid[0].eq(~self.data_pid[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.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)
                    with m.Elif(~in_stream.ready | packet_completing):
                        m.next = "WAIT_TO_SEND"
                        m.d.usb += self.data_pid[0].eq(~self.data_pid[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
Exemplo n.º 14
0
Arquivo: memory.py Projeto: zyp/luna
    def elaborate(self, platform):
        m = Module()

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

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

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

            write_port.data .eq(self.write_data),
            write_port.en   .eq(self.write_en & ~self.full)
        ]

        #
        # Write port.
        #

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

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

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

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


        #
        # Read port.
        #

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


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


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


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

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

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


        #
        # FIFO status.
        #

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

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

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


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

        return m
Exemplo n.º 15
0
    def elaborate(self, _: Platform) -> Module:
        """Implements the logic of the interrupt card."""
        m = Module()

        m.d.comb += [
            self._pend_mti.eq(0),
            self._pend_mei.eq(0),
            self._clear_pend_mti.eq(0),
            self._clear_pend_mei.eq(0),
        ]

        with m.If(~self.trap):
            with m.If(self._mstatus[MStatus.MIE]):

                with m.If(self._mie[MInterrupt.MTI]):
                    with m.If(~self._mip[MInterrupt.MTI]):
                        m.d.comb += self._pend_mti.eq(self.time_irq)
                with m.Else():
                    m.d.comb += self._clear_pend_mti.eq(1)

                with m.If(self._mie[MInterrupt.MEI]):
                    with m.If(~self._mip[MInterrupt.MEI]):
                        m.d.comb += self._pend_mei.eq(self.ext_irq)
                with m.Else():
                    m.d.comb += self._clear_pend_mei.eq(1)

            with m.Else():
                m.d.comb += self._clear_pend_mti.eq(1)
                m.d.comb += self._clear_pend_mei.eq(1)

        m.d.comb += self.mei_pend.eq(self._mip[MInterrupt.MEI])
        m.d.comb += self.mti_pend.eq(self._mip[MInterrupt.MTI])

        enter_trap_mstatus = self._mstatus
        enter_trap_mstatus &= ~(1 << MStatus.MIE)  # clear MIE
        enter_trap_mstatus &= ~(1 << MStatus.MPIE)  # clear MPIE
        enter_trap_mstatus |= (self._mstatus[MStatus.MIE] << MStatus.MPIE
                               )  # set MPIE

        exit_trap_mstatus = self._mstatus
        exit_trap_mstatus |= (1 << MStatus.MPIE)  # set MPIE
        exit_trap_mstatus &= ~(1 << MStatus.MIE)  # clear MIE
        exit_trap_mstatus |= (self._mstatus[MStatus.MPIE] << MStatus.MIE
                              )  # set MIE

        self.multiplex_to_reg(m,
                              clk="ph2w",
                              reg=self._mstatus,
                              sels=[
                                  self.z_to_csr &
                                  (self.csr_num == CSRAddr.MSTATUS),
                                  self.enter_trap,
                                  self.exit_trap,
                              ],
                              sigs=[
                                  self.data_z_in,
                                  enter_trap_mstatus,
                                  exit_trap_mstatus,
                              ],
                              ext_init=self._ext_init)

        self.multiplex_to_reg(m,
                              clk="ph2w",
                              reg=self._mie,
                              sels=[
                                  self.z_to_csr &
                                  (self.csr_num == CSRAddr.MIE),
                              ],
                              sigs=[self.data_z_in],
                              ext_init=self._ext_init)

        mtip = Signal()
        meip = Signal()

        m.d.comb += mtip.eq(self._mip[MInterrupt.MTI])
        m.d.comb += meip.eq(self._mip[MInterrupt.MEI])
        with m.If(self._pend_mti):
            m.d.comb += mtip.eq(1)
        with m.Elif(self._clear_pend_mti | self.clear_pend_mti):
            m.d.comb += mtip.eq(0)
        with m.If(self._pend_mei):
            m.d.comb += meip.eq(1)
        with m.Elif(self._clear_pend_mei | self.clear_pend_mei):
            m.d.comb += meip.eq(0)

        # Pending machine interrupts are not writable.
        mip_load = Signal(32)
        m.d.comb += mip_load.eq(self.data_z_in)
        m.d.comb += mip_load[MInterrupt.MTI].eq(mtip)
        m.d.comb += mip_load[MInterrupt.MEI].eq(meip)
        m.d.comb += mip_load[MInterrupt.MSI].eq(self._mip[MInterrupt.MSI])

        load_mip = self.z_to_csr & (self.csr_num == CSRAddr.MIP)

        mip_pend = Signal(32)
        m.d.comb += mip_pend.eq(self._mip)
        m.d.comb += mip_pend[MInterrupt.MTI].eq(mtip)
        m.d.comb += mip_pend[MInterrupt.MEI].eq(meip)

        # Either we load MIP, or set/clear/retain bits in MIP. We never have
        # to leave MIP alone.

        self.multiplex_to_reg(m,
                              clk="ph2w",
                              reg=self._mip,
                              sels=[load_mip, ~load_mip],
                              sigs=[mip_load, mip_pend])

        self.multiplex_to_bus(
            m,
            bus=self.data_x_out,
            sels=[
                self.csr_to_x & (self.csr_num == CSRAddr.MSTATUS),
                self.csr_to_x & (self.csr_num == CSRAddr.MIE),
                self.csr_to_x & (self.csr_num == CSRAddr.MIP),
            ],
            sigs=[
                self._mstatus,
                self._mie,
                self._mip,
            ])

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

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

        # Hook up clocks and reset to pins

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

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

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

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

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

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

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

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

        return m
Exemplo n.º 17
0
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        m.domains.ramg = ClockDomain(async_reset=True, local=True)
        m.domains.romb0 = ClockDomain(async_reset=True, local=True)
        m.domains.romb1 = ClockDomain(async_reset=True, local=True)
        m.domains.ramb = ClockDomain(async_reset=True, local=True)

        ramg_clk = ClockSignal("ramg")
        romb0_clk = ClockSignal("romb0")
        romb1_clk = ClockSignal("romb1")
        ramb_clk = ClockSignal("ramb")

        m.d.comb += [
            ResetSignal("ramg").eq(self.cart_rst),
            ResetSignal("romb0").eq(self.cart_rst),
            ResetSignal("romb1").eq(self.cart_rst),
            ResetSignal("ramb").eq(self.cart_rst),
        ]

        ramg = Signal(8)
        romb0 = Signal(8, reset=0x01)
        romb1 = Signal(1)
        ramb = Signal(4)

        m.d.ramg += ramg.eq(self.cart_data)
        m.d.romb0 += romb0.eq(self.cart_data)
        m.d.romb1 += romb1.eq(self.cart_data)
        m.d.ramb += ramb.eq(self.cart_data)

        m.d.comb += [
            ramg_clk.eq(1),
            romb0_clk.eq(1),
            romb1_clk.eq(1),
            ramb_clk.eq(1)
        ]
        with m.If(self.cart_wr):
            with m.Switch(self.cart_addr[12:]):
                with m.Case(0b0000):
                    m.d.comb += ramg_clk.eq(0)
                with m.Case(0b0001):
                    m.d.comb += ramg_clk.eq(0)
                with m.Case(0b0010):
                    m.d.comb += romb0_clk.eq(0)
                with m.Case(0b0011):
                    m.d.comb += romb1_clk.eq(0)
                with m.Case(0b0100):
                    m.d.comb += ramb_clk.eq(0)
                with m.Case(0b0101):
                    m.d.comb += ramb_clk.eq(0)

        m.d.comb += [
            self.ram_en.eq(ramg == 0x0A),
            self.ram_bank.eq(ramb),
        ]
        with m.If(self.cart_addr[14]):
            m.d.comb += self.rom_bank.eq(Cat(romb0, romb1))
        with m.Else():
            m.d.comb += self.rom_bank.eq(0)

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

        # pins
        ft_clkout_i = platform.request("ft_clkout_i")
        ft_wr_n_o = platform.request("ft_wr_n_o")
        ft_txe_n_i = platform.request("ft_txe_n_i")
        ft_suspend_n_i = platform.request("ft_suspend_n_i")
        ft_oe_n_o = platform.request("ft_oe_n_o")
        ft_rd_n_o = platform.request("ft_rd_n_o")
        ft_siwua_n_o = platform.request("ft_siwua_n_o")
        ft_data_io = platform.request("ft_data_io")
        adc_d_i = platform.request("adc_d_i")
        adc_oe_o = platform.request("adc_oe_o")
        adc_shdn_o = platform.request("adc_shdn_o")
        ext1 = platform.request("ext1")
        pa_en_n_o = platform.request("pa_en_n_o")
        mix_en_n_o = platform.request("mix_en_n_o")

        # signals
        clk80 = Signal()
        pll_fb = Signal()
        chan_a = Signal(self.ADC_WIDTH)
        chan_b = Signal(self.ADC_WIDTH)
        lsb = Signal()
        lock = Signal(RAW_STATE)
        sample_ctr = Signal(range(self.DECIMATE * self.FFT_LEN))
        sample_ctr_max = Const(self.DECIMATE * self.FFT_LEN - 1)
        cons_done = Signal()
        cons_done_clk80_dom = Signal()
        send_start = Signal()
        send_stop = Signal()
        wait_prod = Signal()
        lock_ftclk_dom = Signal()
        lock_ftclk_dom_last = Signal()

        # clock domains
        clk40_neg = ClockDomain("clk40_neg", clk_edge="neg")
        m.domains.clk40_neg = clk40_neg
        m.d.comb += ClockSignal("clk40_neg").eq(ClockSignal("sync"))

        m.domains += ClockDomain("clk60")
        m.d.comb += ClockSignal("clk60").eq(ft_clkout_i.i)
        m.domains += ClockDomain("clk80")
        m.d.comb += ClockSignal("clk80").eq(clk80)

        # ======================== submodules ========================
        # PLL
        m.submodules += Instance(
            "PLLE2_BASE",
            ("p", "CLKFBOUT_MULT", 24),
            ("p", "DIVCLK_DIVIDE", 1),
            ("p", "CLKOUT0_DIVIDE", 12),
            ("p", "CLKIN1_PERIOD", 25),
            ("o", "CLKOUT0", clk80),
            ("i", "CLKIN1", ClockSignal("sync")),
            ("i", "RST", 0),
            ("o", "CLKFBOUT", pll_fb),
            ("i", "CLKFBIN", pll_fb),
        )

        # ADC
        m.submodules.ltc2292 = ltc2292 = LTC2292(
            posedge_domain="sync", negedge_domain="clk40_neg"
        )
        m.d.comb += [
            ltc2292.di.eq(adc_d_i.i),
            chan_a.eq(ltc2292.dao),
            chan_b.eq(ltc2292.dbo),
        ]

        # FIFO
        m.submodules.fifo = fifo = AsyncFIFO(
            width=self.USB_WIDTH,
            depth=self.DECIMATE * self.FFT_LEN * 2,
            r_domain="clk60",
            w_domain="clk80",
        )
        with m.If(lsb):
            m.d.comb += fifo.w_data.eq(chan_a[: self.USB_WIDTH])
        with m.Else():
            m.d.comb += fifo.w_data.eq(
                Cat(
                    chan_a[self.USB_WIDTH :],
                    Const(0, 2 * self.USB_WIDTH - self.ADC_WIDTH),
                )
            )

        # consumption done sync
        m.submodules.cons_done_sync = cons_done_sync = FFSynchronizer(
            i=cons_done, o=cons_done_clk80_dom, o_domain="clk80"
        )

        # lock synch
        m.submodules.lock_sync = lock_sync = FFSynchronizer(
            i=lock, o=lock_ftclk_dom, o_domain="clk60"
        )

        # =========================== logic ==========================
        m.d.comb += [
            pa_en_n_o.o.eq(1),
            mix_en_n_o.o.eq(1),
            adc_oe_o.o.eq(0b01),
            adc_shdn_o.o.eq(0b00),
            ext1.o[0].eq(0b0),
            ext1.o[3].eq(lock),
            ext1.o[1].eq(0b0),
            ext1.o[4].eq(fifo.r_en),
            ext1.o[2].eq(0b0),
            ext1.o[5].eq(fifo.w_en),
        ]

        # write clock domain
        with m.If(lock == RAW_STATE.PROD):
            with m.If(sample_ctr == sample_ctr_max):
                m.d.clk80 += [
                    lock.eq(RAW_STATE.CONS),
                    sample_ctr.eq(0),
                    lsb.eq(0),
                ]
            with m.Else():
                with m.If(lsb):
                    m.d.clk80 += sample_ctr.eq(sample_ctr + 1)
                m.d.clk80 += lsb.eq(~lsb)
        with m.Else():
            with m.If(cons_done_clk80_dom):
                m.d.clk80 += [
                    lock.eq(RAW_STATE.PROD),
                    sample_ctr.eq(0),
                    lsb.eq(0),
                ]

        with m.Switch(lock):
            with m.Case(RAW_STATE.PROD):
                m.d.comb += fifo.w_en.eq(1)
            with m.Case(RAW_STATE.CONS):
                m.d.comb += fifo.w_en.eq(0)

        # read clock domain
        m.d.clk60 += lock_ftclk_dom_last.eq(lock_ftclk_dom)
        with m.If(lock_ftclk_dom == RAW_STATE.CONS & ~wait_prod):
            with m.If(~fifo.r_rdy):
                m.d.clk60 += wait_prod.eq(1)
        with m.Elif(lock_ftclk_dom == RAW_STATE.CONS):
            m.d.clk60 += wait_prod.eq(1)
        with m.Else():
            m.d.clk60 += wait_prod.eq(0)

        m.d.comb += [
            ft_oe_n_o.o.eq(1),
            ft_rd_n_o.o.eq(1),
            ft_siwua_n_o.o.eq(1),
        ]
        with m.Switch(lock_ftclk_dom):
            with m.Case(RAW_STATE.PROD):
                m.d.comb += [
                    send_start.eq(0),
                    send_stop.eq(0),
                    ft_data_io.o.eq(0),
                    ft_wr_n_o.o.eq(1),
                    fifo.r_en.eq(0),
                ]
            with m.Case(RAW_STATE.CONS):
                with m.If(lock_ftclk_dom_last == RAW_STATE.PROD):
                    m.d.comb += send_start.eq(1)
                with m.Else():
                    m.d.comb += send_start.eq(0)

                with m.If(~fifo.r_rdy):
                    m.d.comb += [send_stop.eq(1), cons_done.eq(1)]
                with m.Else():
                    m.d.comb += [send_stop.eq(0), cons_done.eq(0)]

                with m.If(send_start):
                    m.d.comb += [
                        ft_data_io.o.eq(self.START_FLAG),
                        ft_wr_n_o.o.eq(ft_txe_n_i.i),
                        fifo.r_en.eq(1),
                    ]
                with m.Elif(send_stop):
                    m.d.comb += [
                        ft_data_io.o.eq(self.STOP_FLAG),
                        ft_wr_n_o.o.eq(ft_txe_n_i.i),
                        fifo.r_en.eq(0),
                    ]
                with m.Else():
                    with m.If(wait_prod):
                        m.d.comb += [
                            ft_data_io.o.eq(0),
                            ft_wr_n_o.o.eq(1),
                            fifo.r_en.eq(0),
                        ]
                    with m.Else():
                        m.d.comb += [
                            ft_data_io.o.eq(fifo.r_data),
                            ft_wr_n_o.o.eq(~(~ft_txe_n_i.i & fifo.r_en)),
                            fifo.r_en.eq(~ft_txe_n_i.i & fifo.r_rdy),
                        ]

        return m
Exemplo n.º 19
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 not data in the FIFO.
            self.data_available.eq(fifo_count != 0),

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

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

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

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

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

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

        # Otherwise, add when data's added, and subtract when data's removed.
        with m.Elif(data_push):
            m.d.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.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"):

                # 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(self.utmi.rx_valid
                                         & self.utmi.rx_active),
                    fifo_new_data.eq(self.utmi.rx_valid & self.utmi.rx_active)
                ]

                # Advance the write pointer each time we receive a bit.
                with m.If(self.utmi.rx_valid & self.utmi.rx_active):
                    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):

                    # 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[7:16]),
                    #mem_write_port.data  .eq(0xAA),
                    mem_write_port.en.eq(1),
                    fifo_new_data.eq(1)
                ]
                m.next = "EOP_2"

            with m.State("EOP_2"):

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

                # Move to the next state, which will either be another capture,
                # or our idle state, depending on whether we have another rx.
                with m.If(self.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),
                    ]

                    # FIXME: capture if rx_valid

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

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

                # Trap here, for now.
                pass

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

                pass

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

        #######################################################################
        # 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 = Signal(2)
        m.d.comb += dpair.eq(Cat(self._usbn, self._usbp))

        # output signals for use by the clock recovery stage
        line_state_dt = Signal()
        line_state_dj = Signal()
        line_state_dk = Signal()
        line_state_se0 = Signal()
        line_state_se1 = Signal()

        # If we are in a transition state, then we can sample the pair and
        # move to the next corresponding line state.
        with m.FSM(domain="usb_io"):
            with m.State("DT"):
                m.d.comb += line_state_dt.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"):
                m.d.comb += line_state_dj.eq(1)
                with m.If(dpair != 0b10):
                    m.next = "DT"

            with m.State("DK"):
                m.d.comb += line_state_dk.eq(1)
                with m.If(dpair != 0b01):
                    m.next = "DT"

            with m.State("SE0"):
                m.d.comb += line_state_se0.eq(1)
                with m.If(dpair != 0b00):
                    m.next = "DT"

            with m.State("SE1"):
                m.d.comb += line_state_se1.eq(1)
                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),

            # flop all the outputs to help with timing
            self.line_state_dj.eq(line_state_dj),
            self.line_state_dk.eq(line_state_dk),
            self.line_state_se0.eq(line_state_se0),
            self.line_state_se1.eq(line_state_se1),
        ]

        with m.If(line_state_dt):
            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
Exemplo n.º 21
0
    def elaborate(self, platform):
        m = Module()

        # Move the pipeline along
        m.d.sync += [
            self.o_rgbrndr.eq(self.i_rgbrndr),
            self.o_arndr.eq(self.i_arndr),
            self.o_zrndr.eq(self.i_zrndr),
            self.o_x_coord.eq(self.i_x_coord),
            self.o_y_coord.eq(self.i_y_coord),
            self.o_z_coord.eq(self.i_z_coord),
            self.o_alpha.eq(self.i_alpha),
        ]

        a_red = Signal(8)
        a_green = Signal(8)
        a_blue = Signal(8)
        with m.Switch(self.i_blend_a):
            with m.Case(BlendRGB.SRC):
                m.d.comb += a_red.eq(self.i_red)
                m.d.comb += a_green.eq(self.i_green)
                m.d.comb += a_blue.eq(self.i_blue)
            with m.Case(BlendRGB.FB):
                m.d.comb += a_red.eq(self.i_fbred)
                m.d.comb += a_green.eq(self.i_fbgreen)
                m.d.comb += a_blue.eq(self.i_fbblue)
            with m.Case(BlendRGB.ZERO):
                m.d.comb += a_red.eq(0)
                m.d.comb += a_green.eq(0)
                m.d.comb += a_blue.eq(0)

        b_red = Signal(8)
        b_green = Signal(8)
        b_blue = Signal(8)
        with m.Switch(self.i_blend_b):
            with m.Case(BlendRGB.SRC):
                m.d.comb += b_red.eq(self.i_red)
                m.d.comb += b_green.eq(self.i_green)
                m.d.comb += b_blue.eq(self.i_blue)
            with m.Case(BlendRGB.FB):
                m.d.comb += b_red.eq(self.i_fbred)
                m.d.comb += b_green.eq(self.i_fbgreen)
                m.d.comb += b_blue.eq(self.i_fbblue)
            with m.Case(BlendRGB.ZERO):
                m.d.comb += b_red.eq(0)
                m.d.comb += b_green.eq(0)
                m.d.comb += b_blue.eq(0)

        c = Signal(8)
        with m.Switch(self.i_blend_c):
            with m.Case(BlendAlpha.SRC):
                m.d.comb += c.eq(self.i_alpha)
            with m.Case(BlendAlpha.FB):
                m.d.comb += c.eq(self.i_fbalpha)
            with m.Case(BlendAlpha.FIX):
                m.d.comb += c.eq(self.i_fix)

        d_red = Signal(8)
        d_green = Signal(8)
        d_blue = Signal(8)
        with m.Switch(self.i_blend_d):
            with m.Case(BlendRGB.SRC):
                m.d.comb += d_red.eq(self.i_red)
                m.d.comb += d_green.eq(self.i_green)
                m.d.comb += d_blue.eq(self.i_blue)
            with m.Case(BlendRGB.FB):
                m.d.comb += d_red.eq(self.i_fbred)
                m.d.comb += d_green.eq(self.i_fbgreen)
                m.d.comb += d_blue.eq(self.i_fbblue)
            with m.Case(BlendRGB.ZERO):
                m.d.comb += d_red.eq(0)
                m.d.comb += d_green.eq(0)
                m.d.comb += d_blue.eq(0)

        with m.If(self.i_enable & (~self.i_alphaen | self.i_alpha[7])):
            m.d.sync += [
                self.o_red.eq((((a_red - b_red) * c) >> 7) + d_red),
                self.o_green.eq((((a_green - b_green) * c) >> 7) + d_green),
                self.o_blue.eq((((a_blue - b_blue) * c) >> 7) + d_blue)
            ]
        with m.Else():
            m.d.sync += [
                self.o_red.eq(self.i_red),
                self.o_green.eq(self.i_green),
                self.o_blue.eq(self.i_blue)
            ]

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

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

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

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

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

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

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

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

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

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

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

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

            # Connect up our clock and reset signals.
            self.ulpi.rst.eq(ResetSignal("usb")),

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

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

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

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

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

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

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

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

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

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

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

        #
        # General state signals.
        #

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

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

        #
        # General control signals.
        #

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

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

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

        m.submodules.transmitter = transmitter = TxPipeline()

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

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

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

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

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

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

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

        # Generate our USB clock strobe, which should pulse at 12MHz.
        m.d.usb_io += transmitter.i_bit_strobe.eq(Rose(ClockSignal("usb")))

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

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

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

        #
        # Test scaffolding.
        #

        if self._standalone:

            # Create our timer...
            m.submodules.timer = timer = USBInterpacketTimer()
            timer.add_interface(interface.timer)

            # ... our CRC generator ...
            m.submodules.crc = crc = USBDataPacketCRC()
            crc.add_interface(interface.data_crc)
            m.d.comb += [
                crc.rx_data    .eq(self.utmi.rx_data),
                crc.rx_valid   .eq(self.utmi.rx_valid),
                crc.tx_valid   .eq(0)
            ]

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


        #
        # Convenience feature:
        #
        # If we have -only- a standard request handler, automatically add a handler that will
        # stall all other requests.
        #
        single_handler = (len(self._request_handlers) == 1)
        if (single_handler and isinstance(self._request_handlers[0], StandardRequestHandler)):

            # Add a handler that will stall any non-standard request.
            stall_condition = lambda setup : setup.type != USBRequestType.STANDARD
            self.add_request_handler(StallOnlyRequestHandler(stall_condition))


        #
        # Submodules
        #

        # Create our SETUP packet decoder.
        m.submodules.setup_decoder = setup_decoder = USBSetupDecoder(utmi=self.utmi)
        m.d.comb += [
            interface.data_crc   .connect(setup_decoder.data_crc),
            interface.tokenizer  .connect(setup_decoder.tokenizer),
            setup_decoder.speed  .eq(interface.speed),

            # And attach our timer interface to both our local users and
            # to our setup decoder.
            interface.timer      .attach(setup_decoder.timer)

        ]


        #
        # Request handler logic.
        #

        # Multiplex the output of each of our request handlers.
        m.submodules.request_mux = request_mux = USBRequestHandlerMultiplexer()
        request_handler = request_mux.shared

        # Add each of our handlers to the endpoint; and add it to our mux.
        for handler in self._request_handlers:

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

            # ... and add it.
            m.submodules[name] = handler
            request_mux.add_interface(handler.interface)


        # ... and hook it up.
        m.d.comb += [
            setup_decoder.packet                   .connect(request_handler.setup),
            interface.tokenizer                    .connect(request_handler.tokenizer),

            request_handler.tx                     .attach(interface.tx),
            interface.handshakes_out.ack           .eq(setup_decoder.ack | request_handler.handshakes_out.ack),
            interface.handshakes_out.nak           .eq(request_handler.handshakes_out.nak),
            interface.handshakes_out.stall         .eq(request_handler.handshakes_out.stall),
            interface.handshakes_in                .connect(request_handler.handshakes_in),

            interface.address_changed              .eq(request_handler.address_changed),
            interface.new_address                  .eq(request_handler.new_address),

            request_handler.active_config          .eq(interface.active_config),
            interface.config_changed               .eq(request_handler.config_changed),
            interface.new_config                   .eq(request_handler.new_config),

            # Fix our data PIDs to DATA1, for now, as we don't support multi-packet responses, yet.
            # Per [USB2.0: 8.5.3], the first packet of the DATA or STATUS phase always carries a DATA1 PID.
            interface.tx_pid_toggle                .eq(request_handler.tx_data_pid)
        ]


        #
        # Core control request handler.
        # Behavior dictated by [USB2, 8.5.3].
        #
        endpoint_targeted = (self.interface.tokenizer.endpoint == self._endpoint_number)
        with m.FSM(domain="usb"):

            # SETUP -- The "SETUP" phase of a control request. We'll wait here
            # until the SetupDetector detects a valid setup packet for us.
            with m.State('SETUP'):

                # We won't do anything until we receive a SETUP token.
                with m.If(setup_decoder.packet.received & endpoint_targeted):

                    # If our SETUP packet indicates we'll have a data stage (wLength > 0)
                    # move to the DATA stage. Otherwise, move directly to the status stage [8.5.3].
                    with m.If(setup_decoder.packet.length):

                        # If this is an device -> host request, expect an IN packet.
                        with m.If(setup_decoder.packet.is_in_request):
                            m.next = 'DATA_IN'

                        # Otherwise, expect an OUT one.
                        with m.Else():
                            m.next = 'DATA_OUT'

                    with m.Else():
                        # If we don't have a data phase, our status phase is always an IN [USB2.0: 8.5.3]
                        m.next = 'STATUS_IN'


            with m.State('DATA_IN'):
                self._handle_setup_reset(m)

                # Wait until we have an IN token, and are allowed to respond to it.
                allowed_to_respond = interface.tokenizer.ready_for_response & endpoint_targeted
                with m.If(allowed_to_respond & interface.tokenizer.is_in):

                    # Notify the request handler to prepare a response.
                    m.d.comb += request_handler.data_requested.eq(1)

                # Once we get an OUT token, we should move on to the STATUS stage. [USB2, 8.5.3]
                with m.If(endpoint_targeted & interface.tokenizer.new_token & interface.tokenizer.is_out):
                    m.next = 'STATUS_OUT'


            with m.State('DATA_OUT'):
                self._handle_setup_reset(m)

                # Pass through our Rx related signals iff we're in the DATA_OUT stage,
                # and the most recent token pointed to our endpoint. This ensures the
                # request handler only ever sees data events related to it; this simplifies
                # the request handler logic significantly.
                with m.If(endpoint_targeted & interface.tokenizer.is_out):
                    m.d.comb += [
                        interface.rx                           .connect(request_handler.rx),
                        request_handler.rx_ready_for_response  .eq(interface.rx_ready_for_response)
                    ]

                # Once we get an IN token, we should move on to the STATUS stage. [USB2, 8.5.3]
                with m.If(interface.tokenizer.new_token & interface.tokenizer.is_in):
                    m.next = 'STATUS_IN'


            # STATUS_IN -- We're currently in the status stage, and we're expecting an IN token.
            # We'll wait for that token.
            with m.State('STATUS_IN'):
                self._handle_setup_reset(m)

                # If we respond to a status-phase IN token, we'll always use a DATA1 PID [USB2.0: 8.5.3]

                # When we get an IN token, the host is looking for a status-stage ZLP.
                # Notify the target handler.
                allowed_to_respond = interface.tokenizer.ready_for_response & endpoint_targeted
                with m.If(allowed_to_respond & interface.tokenizer.is_in):
                    m.d.comb += request_handler.status_requested.eq(1)


            # STATUS_OUT -- We're currently in the status stage, and we're expecting the DATA packet for
            # an OUT request.
            with m.State('STATUS_OUT'):
                self._handle_setup_reset(m)

                # Once we've received a new DATA packet, we're ready to handle a status request.
                allowed_to_respond = interface.rx_ready_for_response & endpoint_targeted
                with m.If(allowed_to_respond & interface.tokenizer.is_out):
                    m.d.comb += request_handler.status_requested.eq(1)

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

        # Move the pipeline along
        m.d.sync += [
            self.o_x_coord.eq(self.i_x_coord),
            self.o_y_coord.eq(self.i_y_coord),
            self.o_z_coord.eq(self.i_z_coord),

            self.o_red.eq(self.i_red),
            self.o_green.eq(self.i_green),
            self.o_blue.eq(self.i_blue),
            self.o_alpha.eq(self.i_alpha)
        ]

        # Alpha Test, relative to AREF.
        test = Signal()

        with m.If(self.i_enable):
            with m.Switch(self.i_test):
                with m.Case(AlphaTestMode.NEVER):
                    m.d.comb += test.eq(0)
                with m.Case(AlphaTestMode.ALWAYS):
                    m.d.comb += test.eq(1)
                with m.Case(AlphaTestMode.LESS):
                    m.d.comb += test.eq(self.i_alpha < self.i_aref)
                with m.Case(AlphaTestMode.LEQUAL):
                    m.d.comb += test.eq(self.i_alpha <= self.i_aref)
                with m.Case(AlphaTestMode.EQUAL):
                    m.d.comb += test.eq(self.i_alpha == self.i_aref)
                with m.Case(AlphaTestMode.GEQUAL):
                    m.d.comb += test.eq(self.i_alpha >= self.i_aref)
                with m.Case(AlphaTestMode.GREATER):
                    m.d.comb += test.eq(self.i_alpha > self.i_aref)
                with m.Case(AlphaTestMode.NOTEQUAL):
                    m.d.comb += test.eq(self.i_alpha != self.i_aref)
        with m.Else():
            m.d.comb += test.eq(1)

        with m.Switch(self.i_failmod):
            with m.Case(AlphaFailMode.KEEP):
                m.d.sync += [
                    self.o_rgbrndr.eq(self.i_rgbrndr & test),
                    self.o_arndr.eq(self.i_arndr & test),
                    self.o_zrndr.eq(self.i_zrndr & test)
                ]
            with m.Case(AlphaFailMode.FB_ONLY):
                m.d.sync += [
                    self.o_rgbrndr.eq(self.i_rgbrndr),
                    self.o_arndr.eq(self.i_arndr),
                    self.o_zrndr.eq(self.i_zrndr & test)
                ]
            with m.Case(AlphaFailMode.ZB_ONLY):
                m.d.sync += [
                    self.o_rgbrndr.eq(self.i_rgbrndr & test),
                    self.o_arndr.eq(self.i_arndr & test),
                    self.o_zrndr.eq(self.i_zrndr)
                ]
            with m.Case(AlphaFailMode.RGB_ONLY):
                # "RGB_ONLY is effective only when the color format is RGBA32.
                # In other formats, operation is made with FB_ONLY." - GS User's Manual
                with m.If(self.i_fbpxfmt == PixelFormat.PSMCT32):
                    m.d.sync += [
                        self.o_rgbrndr.eq(self.i_rgbrndr),
                        self.o_arndr.eq(self.i_arndr & test),
                        self.o_zrndr.eq(self.i_zrndr & test)
                    ]
                with m.Else():
                    m.d.sync += [
                        self.o_rgbrndr.eq(self.i_rgbrndr),
                        self.o_arndr.eq(self.i_arndr),
                        self.o_zrndr.eq(self.i_zrndr & test)
                    ]

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

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

        # Create a set of registers, and expose them over SPI.
        board_spi = platform.request("debug_spi")
        spi_registers = SPIRegisterInterface(default_read_value=-1)
        m.submodules.spi_registers = spi_registers

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

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

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

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

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

        #
        # User IO GPIO registers.
        #

        # Data direction register.
        user_io_dir = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4)

        # Pin (input) state register.
        user_io_in = Signal(4)
        spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in)

        # Output value register.
        user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4)

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

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

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

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

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

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

        #
        # SPI flash passthrough connections.
        #
        flash_sdo = Signal()

        spi_flash_bus = platform.request('spi_flash')
        spi_flash_passthrough = ECP5ConfigurationFlashInterface(
            bus=spi_flash_bus)

        m.submodules += spi_flash_passthrough
        m.d.comb += [
            spi_flash_passthrough.sck.eq(board_spi.sck),
            spi_flash_passthrough.sdi.eq(board_spi.sdi),
            flash_sdo.eq(spi_flash_passthrough.sdo),
        ]

        #
        # Synchronize each of our I/O SPI signals, where necessary.
        #
        spi = synchronize(m, board_spi)

        # Select the passthrough or gateware SPI based on our chip-select values.
        gateware_sdo = Signal()
        with m.If(spi_registers.spi.cs):
            m.d.comb += board_spi.sdo.eq(gateware_sdo)
        with m.Else():
            m.d.comb += board_spi.sdo.eq(flash_sdo)

        # Connect our register interface to our board SPI.
        m.d.comb += [
            spi_registers.spi.sck.eq(spi.sck),
            spi_registers.spi.sdi.eq(spi.sdi),
            gateware_sdo.eq(spi_registers.spi.sdo),
            spi_registers.spi.cs.eq(spi.cs)
        ]

        return m
Exemplo n.º 28
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
Exemplo n.º 29
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
Exemplo n.º 30
0
Arquivo: psram.py Projeto: zyp/luna
    def elaborate(self, platform):
        m = Module()

        #
        # Delayed input and output.
        #

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

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

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

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

        with m.If(reset_clock):
            m.d.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), self.bus.dq.oe.eq(1)]

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

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

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

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

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

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

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

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

                    with m.If(extra_latency):
                        m.d.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'

            # 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'

            # TODO: implement write shift states

            with m.State("WRITE_DATA_MSB"):
                pass

        return m