Example #1
0
    def __init__(self, pads, cl=2):
        pads = PHYPadsCombiner(pads)
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        assert databits % 8 == 0

        # PHY settings -----------------------------------------------------------------------------
        self.settings = PhySettings(memtype="SDR",
                                    databits=databits,
                                    dfi_databits=databits,
                                    nranks=nranks,
                                    nphases=1,
                                    rdphase=0,
                                    wrphase=0,
                                    rdcmdphase=0,
                                    wrcmdphase=0,
                                    cl=cl,
                                    read_latency=cl + 2,
                                    write_latency=0)

        # DFI Interface ----------------------------------------------------------------------------
        self.dfi = dfi = Interface(addressbits, bankbits, nranks, databits)

        # # #

        # Iterate on pads groups -------------------------------------------------------------------
        for pads_group in range(len(pads.groups)):
            pads.sel_group(pads_group)

            # Addresses and Commands ---------------------------------------------------------------
            self.sync += [
                pads.a.eq(dfi.p0.address),
                pads.ba.eq(dfi.p0.bank),
                pads.cas_n.eq(dfi.p0.cas_n),
                pads.ras_n.eq(dfi.p0.ras_n),
                pads.we_n.eq(dfi.p0.we_n)
            ]
            if hasattr(pads, "cke"):
                self.sync += pads.cke.eq(dfi.p0.cke)
            if hasattr(pads, "cs_n"):
                self.sync += pads.cs_n.eq(dfi.p0.cs_n)

        # DQ/DQS/DM Data ---------------------------------------------------------------------------
        dq_o = Signal(databits)
        dq_oe = Signal()
        dq_i = Signal(databits)
        self.sync += dq_o.eq(dfi.p0.wrdata)
        for i in range(len(pads.dq)):
            self.specials += Tristate(pads.dq[i], dq_o[i], dq_oe, dq_i[i])
        if hasattr(pads, "dm"):
            assert len(pads.dm) * 8 == databits
            for i in range(len(pads.dm)):
                self.sync += \
                    If(dfi.p0.wrdata_en,
                        pads.dm[i].eq(dfi.p0.wrdata_mask)
                    ).Else(
                        pads.dm[i].eq(0)
                    )
        dq_in = Signal(databits)
        self.sync.sys_ps += dq_in.eq(dq_i)
        self.sync += dfi.p0.rddata.eq(dq_in)

        # DQ/DM Control ----------------------------------------------------------------------------
        wrdata_en = Signal()
        self.sync += wrdata_en.eq(dfi.p0.wrdata_en)
        self.comb += dq_oe.eq(wrdata_en)

        rddata_en = Signal(cl + 2)
        self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en[:cl + 1]))
        self.comb += dfi.p0.rddata_valid.eq(rddata_en[cl + 1])
Example #2
0
    def __init__(self,
                 pads,
                 sys_clk_freq=100e6,
                 cl=None,
                 cwl=None,
                 cmd_delay=0,
                 clk_polarity=0):
        assert isinstance(cmd_delay, int) and cmd_delay < 128
        pads = PHYPadsCombiner(pads)
        memtype = "DDR3"
        tck = 2 / (2 * 2 * sys_clk_freq)
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        nphases = 2
        assert databits % 8 == 0

        # Init -------------------------------------------------------------------------------------
        self.submodules.init = ECP5DDRPHYInit()

        # Parameters -------------------------------------------------------------------------------
        cl = get_default_cl(memtype, tck) if cl is None else cl
        cwl = get_default_cwl(memtype, tck) if cwl is None else cwl
        cl_sys_latency = get_sys_latency(nphases, cl)
        cwl_sys_latency = get_sys_latency(nphases, cwl)

        # Registers --------------------------------------------------------------------------------
        self._dly_sel = CSRStorage(databits // 8)

        self._rdly_dq_rst = CSR()
        self._rdly_dq_inc = CSR()
        self._rdly_dq_bitslip_rst = CSR()
        self._rdly_dq_bitslip = CSR()

        self._burstdet_clr = CSR()
        self._burstdet_seen = CSRStatus(databits // 8)

        # Observation
        self.datavalid = Signal(databits // 8)

        # PHY settings -----------------------------------------------------------------------------
        rdphase = get_sys_phase(nphases, cl_sys_latency, cl)
        wrphase = get_sys_phase(nphases, cwl_sys_latency, cwl)
        self.settings = PhySettings(phytype="ECP5DDRPHY",
                                    memtype=memtype,
                                    databits=databits,
                                    dfi_databits=4 * databits,
                                    nranks=nranks,
                                    nphases=nphases,
                                    rdphase=rdphase,
                                    wrphase=wrphase,
                                    cl=cl,
                                    cwl=cwl,
                                    read_latency=cl_sys_latency + 10,
                                    write_latency=cwl_sys_latency)

        # DFI Interface ----------------------------------------------------------------------------
        self.dfi = dfi = Interface(addressbits, bankbits, nranks, 4 * databits,
                                   nphases)

        # # #

        bl8_chunk = Signal()

        # Iterate on pads groups -------------------------------------------------------------------
        for pads_group in range(len(pads.groups)):
            pads.sel_group(pads_group)

            # Clock --------------------------------------------------------------------------------
            clk_pattern = {0: 0b1010, 1: 0b0101}[clk_polarity]
            for i in range(len(pads.clk_p)):
                pad_oddrx2f = Signal()
                self.specials += Instance(
                    "ODDRX2F",
                    i_RST=ResetSignal("sys"),
                    i_SCLK=ClockSignal("sys"),
                    i_ECLK=ClockSignal("sys2x"),
                    **{f"i_D{n}": (clk_pattern >> n) & 0b1
                       for n in range(4)},
                    o_Q=pad_oddrx2f)
                self.specials += Instance("DELAYG",
                                          p_DEL_VALUE=cmd_delay,
                                          i_A=pad_oddrx2f,
                                          o_Z=pads.clk_p[i])

            # Commands -----------------------------------------------------------------------------
            commands = {
                # Pad name: (DFI name,   Pad type (required or optional))
                "reset_n": ("reset_n", "optional"),
                "cs_n": ("cs_n", "optional"),
                "a": ("address", "required"),
                "ba": ("bank", "required"),
                "ras_n": ("ras_n", "required"),
                "cas_n": ("cas_n", "required"),
                "we_n": ("we_n", "required"),
                "cke": ("cke", "optional"),
                "odt": ("odt", "optional"),
            }
            for pad_name, (dfi_name, pad_type) in commands.items():
                pad = getattr(pads, pad_name, None)
                if (pad is None):
                    if (pad_type == "required"):
                        raise ValueError(
                            f"DRAM pad {pad_name} required but not found in pads."
                        )
                    continue
                for i in range(len(pad)):
                    pad_oddrx2f = Signal()
                    self.specials += Instance("ODDRX2F",
                                              i_RST=ResetSignal("sys"),
                                              i_SCLK=ClockSignal("sys"),
                                              i_ECLK=ClockSignal("sys2x"),
                                              **{
                                                  f"i_D{n}": getattr(
                                                      dfi.phases[n // 2],
                                                      dfi_name)[i]
                                                  for n in range(4)
                                              },
                                              o_Q=pad_oddrx2f)
                    self.specials += Instance("DELAYG",
                                              p_DEL_VALUE=cmd_delay,
                                              i_A=pad_oddrx2f,
                                              o_Z=pad[i])

        # DQS/DM/DQ --------------------------------------------------------------------------------
        dq_oe = Signal()
        dqs_re = Signal()
        dqs_oe = Signal()
        dqs_postamble = Signal()
        dqs_preamble = Signal()
        for i in range(databits // 8):
            # DQSBUFM
            dqs_i = Signal()
            dqsr90 = Signal()
            dqsw270 = Signal()
            dqsw = Signal()
            rdpntr = Signal(3)
            wrpntr = Signal(3)
            rdly = Signal(7)
            burstdet = Signal()
            self.sync += [
                If(self._dly_sel.storage[i] & self._rdly_dq_rst.re,
                   rdly.eq(0)),
                If(self._dly_sel.storage[i] & self._rdly_dq_inc.re,
                   rdly.eq(rdly + 1))
            ]
            self.specials += Instance(
                "DQSBUFM",
                p_DQS_LI_DEL_ADJ="MINUS",
                p_DQS_LI_DEL_VAL=1,
                p_DQS_LO_DEL_ADJ="MINUS",
                p_DQS_LO_DEL_VAL=4,
                # Clocks / Reset
                i_RST=ResetSignal("sys"),
                i_SCLK=ClockSignal("sys"),
                i_ECLK=ClockSignal("sys2x"),
                i_DDRDEL=self.init.delay,
                i_PAUSE=self.init.pause | self._dly_sel.storage[i],

                # Control
                # Assert LOADNs to use DDRDEL control
                i_RDLOADN=0,
                i_RDMOVE=0,
                i_RDDIRECTION=1,
                i_WRLOADN=0,
                i_WRMOVE=0,
                i_WRDIRECTION=1,

                # Reads (generate shifted DQS clock for reads)
                i_READ0=dqs_re,
                i_READ1=dqs_re,
                **{f"i_READCLKSEL{n}": rdly[n]
                   for n in range(3)},
                i_DQSI=dqs_i,
                o_DQSR90=dqsr90,
                **{f"o_RDPNTR{n}": rdpntr[n]
                   for n in range(3)},
                **{f"o_WRPNTR{n}": wrpntr[n]
                   for n in range(3)},
                o_DATAVALID=self.datavalid[i],
                o_BURSTDET=burstdet,

                # Writes (generate shifted ECLK clock for writes)
                o_DQSW270=dqsw270,
                o_DQSW=dqsw)
            burstdet_d = Signal()
            self.sync += [
                burstdet_d.eq(burstdet),
                If(self._burstdet_clr.re, self._burstdet_seen.status[i].eq(0)),
                If(burstdet & ~burstdet_d,
                   self._burstdet_seen.status[i].eq(1)),
            ]

            # DQS ----------------------------------------------------------------------------------
            dqs = Signal()
            dqs_oe_n = Signal()
            self.specials += [
                Instance("ODDRX2DQSB",
                         i_RST=ResetSignal("sys"),
                         i_SCLK=ClockSignal("sys"),
                         i_ECLK=ClockSignal("sys2x"),
                         i_DQSW=dqsw,
                         **{f"i_D{n}": (0b1010 >> n) & 0b1
                            for n in range(4)},
                         o_Q=dqs),
                Instance("TSHX2DQSA",
                         i_RST=ResetSignal("sys"),
                         i_SCLK=ClockSignal("sys"),
                         i_ECLK=ClockSignal("sys2x"),
                         i_DQSW=dqsw,
                         i_T0=~(dqs_oe | dqs_postamble),
                         i_T1=~(dqs_oe | dqs_preamble),
                         o_Q=dqs_oe_n),
                Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i)
            ]

            # DM -----------------------------------------------------------------------------------
            dm_o_data = Signal(8)
            dm_o_data_d = Signal(8)
            dm_o_data_muxed = Signal(4)
            for n in range(8):
                self.comb += dm_o_data[n].eq(
                    dfi.phases[n // 4].wrdata_mask[n % 4 * databits // 8 + i])
            self.sync += dm_o_data_d.eq(dm_o_data)
            dm_bl8_cases = {}
            dm_bl8_cases[0] = dm_o_data_muxed.eq(dm_o_data[:4])
            dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:])
            self.sync += Case(bl8_chunk, dm_bl8_cases)
            self.specials += Instance(
                "ODDRX2DQA",
                i_RST=ResetSignal("sys"),
                i_SCLK=ClockSignal("sys"),
                i_ECLK=ClockSignal("sys2x"),
                i_DQSW270=dqsw270,
                **{f"i_D{n}": dm_o_data_muxed[n]
                   for n in range(4)},
                o_Q=pads.dm[i])

            # DQ -----------------------------------------------------------------------------------
            for j in range(8 * i, 8 * (i + 1)):
                dq_o = Signal()
                dq_i = Signal()
                dq_oe_n = Signal()
                dq_i_delayed = Signal()
                dq_i_data = Signal(8)
                dq_o_data = Signal(8)
                dq_o_data_d = Signal(8)
                dq_o_data_muxed = Signal(4)
                for n in range(8):
                    self.comb += dq_o_data[n].eq(
                        dfi.phases[n // 4].wrdata[n % 4 * databits + j])
                self.sync += dq_o_data_d.eq(dq_o_data)
                dq_bl8_cases = {}
                dq_bl8_cases[0] = dq_o_data_muxed.eq(dq_o_data[:4])
                dq_bl8_cases[1] = dq_o_data_muxed.eq(dq_o_data_d[4:])
                self.sync += Case(bl8_chunk, dq_bl8_cases)
                self.specials += [
                    Instance(
                        "ODDRX2DQA",
                        i_RST=ResetSignal("sys"),
                        i_SCLK=ClockSignal("sys"),
                        i_ECLK=ClockSignal("sys2x"),
                        i_DQSW270=dqsw270,
                        **{f"i_D{n}": dq_o_data_muxed[n]
                           for n in range(4)},
                        o_Q=dq_o)
                ]
                dq_i_bitslip = BitSlip(4,
                                       rst=self._dly_sel.storage[i]
                                       & self._rdly_dq_bitslip_rst.re,
                                       slp=self._dly_sel.storage[i]
                                       & self._rdly_dq_bitslip.re,
                                       cycles=1)
                self.submodules += dq_i_bitslip
                self.specials += [
                    Instance("DELAYG",
                             p_DEL_MODE="DQS_ALIGNED_X2",
                             i_A=dq_i,
                             o_Z=dq_i_delayed),
                    Instance(
                        "IDDRX2DQA",
                        i_RST=ResetSignal("sys"),
                        i_SCLK=ClockSignal("sys"),
                        i_ECLK=ClockSignal("sys2x"),
                        i_DQSR90=dqsr90,
                        **{f"i_RDPNTR{n}": rdpntr[n]
                           for n in range(3)},
                        **{f"i_WRPNTR{n}": wrpntr[n]
                           for n in range(3)},
                        i_D=dq_i_delayed,
                        **{f"o_Q{n}": dq_i_bitslip.i[n]
                           for n in range(4)},
                    )
                ]
                dq_i_bitslip_o_d = Signal(4)
                self.sync += dq_i_bitslip_o_d.eq(dq_i_bitslip.o)
                self.comb += dq_i_data.eq(Cat(dq_i_bitslip_o_d,
                                              dq_i_bitslip.o))
                for n in range(8):
                    self.comb += dfi.phases[n // 4].rddata[n % 4 * databits +
                                                           j].eq(dq_i_data[n])
                self.specials += [
                    Instance(
                        "TSHX2DQA",
                        i_RST=ResetSignal("sys"),
                        i_SCLK=ClockSignal("sys"),
                        i_ECLK=ClockSignal("sys2x"),
                        i_DQSW270=dqsw270,
                        i_T0=~dq_oe,
                        i_T1=~dq_oe,
                        o_Q=dq_oe_n,
                    ),
                    Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i)
                ]

        # Read Control Path ------------------------------------------------------------------------
        rdtap = cl_sys_latency

        # Creates a delay line of read commands coming from the DFI interface. The taps are used to
        # control DQS read (internal read pulse of the DQSBUF) and the output of the delay is used
        # signal a valid read data to the DFI interface.
        #
        # The DQS read must be asserted for 2 sys_clk cycles before the read data is coming back from
        # the DRAM (see 6.2.4 READ Pulse Positioning Optimization of FPGA-TN-02035-1.2)
        #
        # The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
        # interface, the latency is the sum of the ODDRX2DQA, CAS, IDDRX2DQA latencies.
        rddata_en = TappedDelayLine(signal=reduce(
            or_, [dfi.phases[i].rddata_en for i in range(nphases)]),
                                    ntaps=self.settings.read_latency)
        self.submodules += rddata_en

        self.comb += [
            phase.rddata_valid.eq(rddata_en.output) for phase in dfi.phases
        ]
        self.comb += dqs_re.eq(rddata_en.taps[rdtap]
                               | rddata_en.taps[rdtap + 1])

        # Write Control Path -----------------------------------------------------------------------
        wrtap = cwl_sys_latency

        # Create a delay line of write commands coming from the DFI interface. This taps are used to
        # control DQ/DQS tristates and to select write data of the DRAM burst from the DFI interface.
        # The PHY is operating in halfrate mode (so provide 4 datas every sys_clk cycles: 2x for DDR,
        # 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency. Writes are
        # then performed in 2 sys_clk cycles and data needs to be selected for each cycle.
        wrdata_en = TappedDelayLine(signal=reduce(
            or_, [dfi.phases[i].wrdata_en for i in range(nphases)]),
                                    ntaps=wrtap + 4)
        self.submodules += wrdata_en

        self.comb += dq_oe.eq(wrdata_en.taps[wrtap]
                              | wrdata_en.taps[wrtap + 1])
        self.comb += bl8_chunk.eq(wrdata_en.taps[wrtap])
        self.comb += dqs_oe.eq(dq_oe)

        # Write DQS Postamble/Preamble Control Path ------------------------------------------------
        # Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
        # write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles:
        # 1 for Preamble, 2 for the Write and 1 for the Postamble.
        self.comb += dqs_preamble.eq(wrdata_en.taps[wrtap - 1]
                                     & ~wrdata_en.taps[wrtap + 0])
        self.comb += dqs_postamble.eq(wrdata_en.taps[wrtap + 2]
                                      & ~wrdata_en.taps[wrtap + 1])
Example #3
0
    def __init__(self, pads, dw=32, timeout=1024):
        read_fifo = ClockDomainsRenamer({
            "write": "usb",
            "read": "sys"
        })(stream.AsyncFIFO(phy_description(dw), 128))
        write_fifo = ClockDomainsRenamer({
            "write": "sys",
            "read": "usb"
        })(stream.AsyncFIFO(phy_description(dw), 128))

        read_buffer = ClockDomainsRenamer("usb")(stream.SyncFIFO(
            phy_description(dw), 4))
        self.comb += read_buffer.source.connect(read_fifo.sink)

        self.submodules += read_fifo
        self.submodules += read_buffer
        self.submodules += write_fifo

        self.read_buffer = read_buffer

        self.sink = write_fifo.sink
        self.source = read_fifo.source

        self.tdata_w = tdata_w = Signal(dw)
        self.data_r = data_r = Signal(dw)
        self.data_oe = data_oe = Signal()
        self.specials += Tristate(pads.data, tdata_w, data_oe, data_r)

        data_w = Signal(dw)
        _data_w = Signal(dw)
        self.sync.usb += [_data_w.eq(data_w)]
        for i in range(dw):
            self.specials += [
                Instance("ODDR",
                         p_DDR_CLK_EDGE="SAME_EDGE",
                         i_C=ClockSignal("usb"),
                         i_CE=1,
                         i_S=0,
                         i_R=0,
                         i_D1=_data_w[i],
                         i_D2=data_w[i],
                         o_Q=tdata_w[i])
            ]

        self.rd_n = rd_n = Signal()
        _rd_n = Signal(reset=1)
        self.wr_n = wr_n = Signal()
        _wr_n = Signal(reset=1)
        self.oe_n = oe_n = Signal()
        _oe_n = Signal(reset=1)
        self.sync.usb += [
            _rd_n.eq(rd_n),
            _wr_n.eq(wr_n),
            _oe_n.eq(oe_n),
        ]
        self.specials += [
            Instance("ODDR",
                     p_DDR_CLK_EDGE="SAME_EDGE",
                     i_C=ClockSignal("usb"),
                     i_CE=1,
                     i_S=0,
                     i_R=0,
                     i_D1=_rd_n,
                     i_D2=rd_n,
                     o_Q=pads.rd_n),
            Instance("ODDR",
                     p_DDR_CLK_EDGE="SAME_EDGE",
                     i_C=ClockSignal("usb"),
                     i_CE=1,
                     i_S=0,
                     i_R=0,
                     i_D1=_wr_n,
                     i_D2=wr_n,
                     o_Q=pads.wr_n),
            Instance("ODDR",
                     p_DDR_CLK_EDGE="SAME_EDGE",
                     i_C=ClockSignal("usb"),
                     i_CE=1,
                     i_S=0,
                     i_R=0,
                     i_D1=_oe_n,
                     i_D2=oe_n,
                     o_Q=pads.oe_n)
        ]

        self.comb += [
            pads.rst.eq(~ResetSignal("usb")),
            pads.be.eq(0xf),
            pads.siwua.eq(1),
            data_oe.eq(oe_n),
        ]

        fsm = FSM()
        self.submodules.fsm = ClockDomainsRenamer("usb")(fsm)

        self.tempsendval = tempsendval = Signal(dw)
        self.temptosend = temptosend = Signal()

        self.tempreadval = tempreadval = Signal(dw)
        self.temptoread = temptoread = Signal()

        self.wants_read = wants_read = Signal()
        self.wants_write = wants_write = Signal()
        self.cnt_write = cnt_write = Signal(max=timeout + 1)
        self.cnt_read = cnt_read = Signal(max=timeout + 1)

        first_write = Signal()

        self.comb += [
            wants_read.eq(~temptoread & ~pads.rxf_n),
            wants_write.eq((temptosend | write_fifo.source.valid)
                           & (pads.txe_n == 0)),
        ]

        self.fsmstate = Signal(4)
        self.comb += [
            self.fsmstate.eq(
                Cat(fsm.ongoing("IDLE"), fsm.ongoing("WRITE"),
                    fsm.ongoing("RDWAIT"), fsm.ongoing("READ")))
        ]

        self.sync.usb += [
            If(~fsm.ongoing("READ"),
               If(temptoread, If(read_buffer.sink.ready, temptoread.eq(0))))
        ]
        self.comb += [
            If(
                ~fsm.ongoing("READ"),
                If(
                    temptoread,
                    read_buffer.sink.data.eq(tempreadval),
                    read_buffer.sink.valid.eq(1),
                ))
        ]

        fsm.act(
            "IDLE", rd_n.eq(1), wr_n.eq(1),
            If(
                wants_write,
                oe_n.eq(1),
                NextValue(cnt_write, 0),
                NextValue(first_write, 1),
                NextState("WRITE"),
            ).Elif(wants_read, oe_n.eq(0),
                   NextState("RDWAIT")).Else(oe_n.eq(1), ))

        fsm.act(
            "WRITE", If(
                wants_read,
                NextValue(cnt_write, cnt_write + 1),
            ), NextValue(first_write, 0), rd_n.eq(1),
            If(
                pads.txe_n, oe_n.eq(1), wr_n.eq(1),
                write_fifo.source.ready.eq(0),
                If(write_fifo.source.valid & ~first_write,
                   NextValue(temptosend, 1)),
                NextState("IDLE")).Elif(
                    temptosend, oe_n.eq(1), data_w.eq(tempsendval), wr_n.eq(0),
                    NextValue(temptosend,
                              0)).Elif(cnt_write > timeout, oe_n.eq(0),
                                       NextState("RDWAIT")).Elif(
                                           write_fifo.source.valid,
                                           oe_n.eq(1),
                                           data_w.eq(write_fifo.source.data),
                                           write_fifo.source.ready.eq(1),
                                           NextValue(tempsendval,
                                                     write_fifo.source.data),
                                           NextValue(temptosend, 0),
                                           wr_n.eq(0),
                                       ).Else(oe_n.eq(1), wr_n.eq(1),
                                              NextValue(temptosend, 0),
                                              NextState("IDLE")))

        fsm.act("RDWAIT", rd_n.eq(0), oe_n.eq(0), wr_n.eq(1),
                NextValue(cnt_read, 0), NextState("READ"))

        fsm.act(
            "READ", If(
                wants_write,
                NextValue(cnt_read, cnt_read + 1),
            ), wr_n.eq(1),
            If(
                pads.rxf_n,
                oe_n.eq(0),
                rd_n.eq(1),
                NextState("IDLE"),
            ).Elif(
                cnt_read > timeout,
                NextValue(cnt_write, 0),
                NextValue(first_write, 1),
                NextState("WRITE"),
                oe_n.eq(1),
            ).Else(
                oe_n.eq(0), read_buffer.sink.valid.eq(1),
                read_buffer.sink.data.eq(data_r),
                NextValue(tempreadval, data_r),
                If(read_buffer.sink.ready,
                   rd_n.eq(0)).Else(NextValue(temptoread, 1),
                                    NextState("IDLE"), rd_n.eq(1))))
    def __init__(self, pads, sys_clk_freq=100e6):
        memtype = "DDR3"
        tck = 2/(2*2*sys_clk_freq)
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        nphases = 2

        # Init -------------------------------------------------------------------------------------
        self.submodules.init = ClockDomainsRenamer("init")(ECP5DDRPHYInit("sys2x"))

        # Registers --------------------------------------------------------------------------------
        self._dly_sel = CSRStorage(databits//8)

        self._rdly_dq_rst = CSR()
        self._rdly_dq_inc = CSR()
        self._rdly_dq_bitslip_rst = CSR()
        self._rdly_dq_bitslip = CSR()

        self._burstdet_clr = CSR()
        self._burstdet_seen = CSRStatus(databits//8)

        # Observation
        self.datavalid = Signal(databits//8)

        # PHY settings -----------------------------------------------------------------------------
        cl, cwl = get_cl_cw(memtype, tck)
        cl_sys_latency = get_sys_latency(nphases, cl)
        cwl_sys_latency = get_sys_latency(nphases, cwl)

        rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
        wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
        self.settings = PhySettings(
            memtype=memtype,
            databits=databits,
            dfi_databits=4*databits,
            nranks=nranks,
            nphases=nphases,
            rdphase=rdphase,
            wrphase=wrphase,
            rdcmdphase=rdcmdphase,
            wrcmdphase=wrcmdphase,
            cl=cl,
            cwl=cwl,
            read_latency=2 + cl_sys_latency + 2 + log2_int(4//nphases) + 6,
            write_latency=cwl_sys_latency
        )

        # DFI Interface ----------------------------------------------------------------------------
        self.dfi = Interface(addressbits, bankbits, nranks, 4*databits, 4)

        # # #

        bl8_sel = Signal()

        # Clock ------------------------------------------------------------------------------------
        for i in range(len(pads.clk_p)):
            sd_clk_se = Signal()
            self.specials += [
                Instance("ODDRX2F",
                    i_D0=0,
                    i_D1=1,
                    i_D2=0,
                    i_D3=1,
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    i_RST=ResetSignal("sys2x"),
                    o_Q=pads.clk_p[i]
                ),
            ]

        # Addresses and Commands -------------------------------------------------------------------
        for i in range(addressbits):
            self.specials += \
                Instance("ODDRX2F",
                    i_D0=self.dfi.phases[0].address[i],
                    i_D1=self.dfi.phases[0].address[i],
                    i_D2=self.dfi.phases[1].address[i],
                    i_D3=self.dfi.phases[1].address[i],
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    i_RST=ResetSignal("sys2x"),
                    o_Q=pads.a[i]
                )
        for i in range(bankbits):
            self.specials += \
                 Instance("ODDRX2F",
                    i_D0=self.dfi.phases[0].bank[i],
                    i_D1=self.dfi.phases[0].bank[i],
                    i_D2=self.dfi.phases[1].bank[i],
                    i_D3=self.dfi.phases[1].bank[i],
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    i_RST=ResetSignal("sys2x"),
                    o_Q=pads.ba[i]
                )
        controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
        if hasattr(pads, "reset_n"):
            controls.append("reset_n")
        if hasattr(pads, "cs_n"):
            controls.append("cs_n")
        for name in controls:
            for i in range(len(getattr(pads, name))):
                self.specials += \
                    Instance("ODDRX2F",
                        i_D0=getattr(self.dfi.phases[0], name)[i],
                        i_D1=getattr(self.dfi.phases[0], name)[i],
                        i_D2=getattr(self.dfi.phases[1], name)[i],
                        i_D3=getattr(self.dfi.phases[1], name)[i],
                        i_ECLK=ClockSignal("sys2x"),
                        i_SCLK=ClockSignal(),
                        i_RST=ResetSignal("sys2x"),
                        o_Q=getattr(pads, name)[i]
                )

        # DQ ---------------------------------------------------------------------------------------
        oe_dq = Signal()
        oe_dqs = Signal()
        dqs_postamble = Signal()
        dqs_preamble = Signal()
        dqs_read = Signal()
        for i in range(databits//8):
            # DQSBUFM
            dqs_i = Signal()
            dqsr90 = Signal()
            dqsw270 = Signal()
            dqsw = Signal()
            rdpntr = Signal(3)
            wrpntr = Signal(3)
            rdly = Signal(7)
            self.sync += \
                If(self._dly_sel.storage[i],
                    If(self._rdly_dq_rst.re,
                        rdly.eq(0),
                    ).Elif(self._rdly_dq_inc.re,
                        rdly.eq(rdly + 1),
                    )
                )
            datavalid = Signal()
            burstdet = Signal()
            self.specials += Instance("DQSBUFM",
                p_DQS_LI_DEL_ADJ="MINUS",
                p_DQS_LI_DEL_VAL=1,
                p_DQS_LO_DEL_ADJ="MINUS",
                p_DQS_LO_DEL_VAL=4,
                # Clocks / Reset
                i_SCLK=ClockSignal("sys"),
                i_ECLK=ClockSignal("sys2x"),
                i_RST=ResetSignal("sys2x"),
                i_DDRDEL=self.init.delay,
                i_PAUSE=self.init.pause | self._dly_sel.storage[i],

                # Control
                # Assert LOADNs to use DDRDEL control
                i_RDLOADN=0,
                i_RDMOVE=0,
                i_RDDIRECTION=1,
                i_WRLOADN=0,
                i_WRMOVE=0,
                i_WRDIRECTION=1,

                # Reads (generate shifted DQS clock for reads)
                i_READ0=dqs_read,
                i_READ1=dqs_read,
                i_READCLKSEL0=rdly[0],
                i_READCLKSEL1=rdly[1],
                i_READCLKSEL2=rdly[2],
                i_DQSI=dqs_i,
                o_DQSR90=dqsr90,
                o_RDPNTR0=rdpntr[0],
                o_RDPNTR1=rdpntr[1],
                o_RDPNTR2=rdpntr[2],
                o_WRPNTR0=wrpntr[0],
                o_WRPNTR1=wrpntr[1],
                o_WRPNTR2=wrpntr[2],
                o_DATAVALID=self.datavalid[i],
                o_BURSTDET=burstdet,

                # Writes (generate shifted ECLK clock for writes)
                o_DQSW270=dqsw270,
                o_DQSW=dqsw
            )
            burstdet_d = Signal()
            self.sync += [
                burstdet_d.eq(burstdet),
                If(self._burstdet_clr.re,
                    self._burstdet_seen.status[i].eq(0)
                ).Elif(burstdet & ~burstdet_d,
                    self._burstdet_seen.status[i].eq(1)
                )
            ]

            # DQS and DM ---------------------------------------------------------------------------
            dqs_serdes_pattern = Signal(8, reset=0b1010)
            dm_o_data = Signal(8)
            dm_o_data_d = Signal(8)
            dm_o_data_muxed = Signal(4)
            self.comb += dm_o_data.eq(Cat(
                self.dfi.phases[0].wrdata_mask[0*databits//8+i], self.dfi.phases[0].wrdata_mask[1*databits//8+i],
                self.dfi.phases[0].wrdata_mask[2*databits//8+i], self.dfi.phases[0].wrdata_mask[3*databits//8+i],
                self.dfi.phases[1].wrdata_mask[0*databits//8+i], self.dfi.phases[1].wrdata_mask[1*databits//8+i],
                self.dfi.phases[1].wrdata_mask[2*databits//8+i], self.dfi.phases[1].wrdata_mask[3*databits//8+i]),
            )
            self.sync += dm_o_data_d.eq(dm_o_data)
            self.sync += \
                If(bl8_sel,
                    dm_o_data_muxed.eq(dm_o_data_d[4:])
                ).Else(
                    dm_o_data_muxed.eq(dm_o_data[:4])
                )
            self.specials += \
                Instance("ODDRX2DQA",
                    i_D0=dm_o_data_muxed[0],
                    i_D1=dm_o_data_muxed[1],
                    i_D2=dm_o_data_muxed[2],
                    i_D3=dm_o_data_muxed[3],
                    i_RST=ResetSignal("sys2x"),
                    i_DQSW270=dqsw270,
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    o_Q=pads.dm[i]
                )

            dqs = Signal()
            dqs_oe_n = Signal()
            self.specials += \
                Instance("ODDRX2DQSB",
                    i_D0=dqs_serdes_pattern[0],
                    i_D1=dqs_serdes_pattern[1],
                    i_D2=dqs_serdes_pattern[2],
                    i_D3=dqs_serdes_pattern[3],
                    i_RST=ResetSignal("sys2x"),
                    i_DQSW=dqsw,
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    o_Q=dqs
                )
            self.specials += \
                Instance("TSHX2DQSA",
                    i_T0=~(oe_dqs|dqs_postamble),
                    i_T1=~(oe_dqs|dqs_preamble),
                    i_SCLK=ClockSignal(),
                    i_ECLK=ClockSignal("sys2x"),
                    i_DQSW=dqsw,
                    i_RST=ResetSignal("sys2x"),
                    o_Q=dqs_oe_n,
                )
            self.specials += Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i)

            for j in range(8*i, 8*(i+1)):
                dq_o = Signal()
                dq_i = Signal()
                dq_oe_n = Signal()
                dq_i_delayed = Signal()
                dq_i_data = Signal(4)
                dq_o_data = Signal(8)
                dq_o_data_d = Signal(8)
                dq_o_data_muxed = Signal(4)
                self.comb += dq_o_data.eq(Cat(
                    self.dfi.phases[0].wrdata[0*databits+j], self.dfi.phases[0].wrdata[1*databits+j],
                    self.dfi.phases[0].wrdata[2*databits+j], self.dfi.phases[0].wrdata[3*databits+j],
                    self.dfi.phases[1].wrdata[0*databits+j], self.dfi.phases[1].wrdata[1*databits+j],
                    self.dfi.phases[1].wrdata[2*databits+j], self.dfi.phases[1].wrdata[3*databits+j])
                )
                self.sync += dq_o_data_d.eq(dq_o_data)
                self.sync += \
                    If(bl8_sel,
                        dq_o_data_muxed.eq(dq_o_data_d[4:])
                    ).Else(
                        dq_o_data_muxed.eq(dq_o_data[:4])
                    )
                self.specials += \
                    Instance("ODDRX2DQA",
                        i_D0=dq_o_data_muxed[0],
                        i_D1=dq_o_data_muxed[1],
                        i_D2=dq_o_data_muxed[2],
                        i_D3=dq_o_data_muxed[3],
                        i_RST=ResetSignal("sys2x"),
                        i_DQSW270=dqsw270,
                        i_ECLK=ClockSignal("sys2x"),
                        i_SCLK=ClockSignal(),
                        o_Q=dq_o
                    )
                self.specials += \
                    Instance("DELAYF",
                        i_A=dq_i,
                        i_LOADN=1,
                        i_MOVE=0,
                        i_DIRECTION=0,
                        o_Z=dq_i_delayed,
                        p_DEL_MODE="DQS_ALIGNED_X2"
                    )
                self.specials += \
                    Instance("IDDRX2DQA",
                        i_D=dq_i_delayed,
                        i_RST=ResetSignal("sys2x"),
                        i_DQSR90=dqsr90,
                        i_SCLK=ClockSignal(),
                        i_ECLK=ClockSignal("sys2x"),
                        i_RDPNTR0=rdpntr[0],
                        i_RDPNTR1=rdpntr[1],
                        i_RDPNTR2=rdpntr[2],
                        i_WRPNTR0=wrpntr[0],
                        i_WRPNTR1=wrpntr[1],
                        i_WRPNTR2=wrpntr[2],
                        o_Q0=dq_i_data[0],
                        o_Q1=dq_i_data[1],
                        o_Q2=dq_i_data[2],
                        o_Q3=dq_i_data[3],
                    )
                dq_bitslip = BitSlip(4)
                self.comb += dq_bitslip.i.eq(dq_i_data)
                self.sync += \
                    If(self._dly_sel.storage[i],
                        If(self._rdly_dq_bitslip_rst.re,
                            dq_bitslip.value.eq(0)
                        ).Elif(self._rdly_dq_bitslip.re,
                            dq_bitslip.value.eq(dq_bitslip.value + 1)
                        )
                    )
                self.submodules += dq_bitslip
                dq_bitslip_o_d = Signal(4)
                self.sync += dq_bitslip_o_d.eq(dq_bitslip.o)
                self.comb += [
                    self.dfi.phases[0].rddata[0*databits+j].eq(dq_bitslip_o_d[0]), self.dfi.phases[0].rddata[1*databits+j].eq(dq_bitslip_o_d[1]),
                    self.dfi.phases[0].rddata[2*databits+j].eq(dq_bitslip_o_d[2]), self.dfi.phases[0].rddata[3*databits+j].eq(dq_bitslip_o_d[3]),
                    self.dfi.phases[1].rddata[0*databits+j].eq(dq_bitslip.o[0]), self.dfi.phases[1].rddata[1*databits+j].eq(dq_bitslip.o[1]),
                    self.dfi.phases[1].rddata[2*databits+j].eq(dq_bitslip.o[2]), self.dfi.phases[1].rddata[3*databits+j].eq(dq_bitslip.o[3]),
                ]
                self.specials += \
                    Instance("TSHX2DQA",
                        i_T0=~oe_dq,
                        i_T1=~oe_dq,
                        i_SCLK=ClockSignal(),
                        i_ECLK=ClockSignal("sys2x"),
                        i_DQSW270=dqsw270,
                        i_RST=ResetSignal("sys2x"),
                        o_Q=dq_oe_n,
                    )
                self.specials += Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i)

        # Flow control -----------------------------------------------------------------------------
        #
        # total read latency:
        #  ODDRX2DQA latency
        #  cl_sys_latency
        #  IDDRX2DQA latency
        rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en
        rddata_ens = Array([Signal() for i in range(self.settings.read_latency-1)])
        for i in range(self.settings.read_latency-1):
            n_rddata_en = Signal()
            self.sync += n_rddata_en.eq(rddata_en)
            self.comb += rddata_ens[i].eq(rddata_en)
            rddata_en = n_rddata_en
        self.sync += [phase.rddata_valid.eq(rddata_en)
            for phase in self.dfi.phases]
        self.comb += dqs_read.eq(rddata_ens[cl_sys_latency+1] | rddata_ens[cl_sys_latency+2])
        oe = Signal()
        last_wrdata_en = Signal(cwl_sys_latency+3)
        wrphase = self.dfi.phases[self.settings.wrphase]
        self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:-1]))
        self.comb += oe.eq(
            last_wrdata_en[cwl_sys_latency-1] |
            last_wrdata_en[cwl_sys_latency]   |
            last_wrdata_en[cwl_sys_latency+1] |
            last_wrdata_en[cwl_sys_latency+2])
        self.sync += oe_dqs.eq(oe), oe_dq.eq(oe)
        self.sync += bl8_sel.eq(last_wrdata_en[cwl_sys_latency-1])
        self.sync += dqs_preamble.eq(last_wrdata_en[cwl_sys_latency-2])
        self.sync += dqs_postamble.eq(oe_dqs)
Example #5
0
    def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"):
        """
        Simple SPI flash.
        Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
        Read). Only supports mode3 (cpol=1, cpha=1).
        """
        SpiFlashCommon.__init__(self, pads)
        self.bus = bus = wishbone.Interface()
        spi_width = len(pads.dq)
        assert spi_width >= 2

        if with_bitbang:
            self.bitbang = CSRStorage(4, reset_less=True, fields=[
                CSRField("mosi", description="Output value for MOSI pin, valid whenever ``dir`` is ``0``."),
                CSRField("clk", description="Output value for SPI CLK pin."),
                CSRField("cs_n", description="Output value for SPI CSn pin."),
                CSRField("dir", description="Sets the direction for *ALL* SPI data pins except CLK and CSn.", values=[
                    ("0", "OUT", "SPI pins are all output"),
                    ("1", "IN", "SPI pins are all input"),
                ])
            ], description="""
                Bitbang controls for SPI output.  Only standard 1x SPI is supported, and as
                a result all four wires are ganged together.  This means that it is only possible
                to perform half-duplex operations, using this SPI core.
            """)
            self.miso = CSRStatus(description="Incoming value of MISO signal.")
            self.bitbang_en = CSRStorage(description="Write a ``1`` here to disable memory-mapped mode and enable bitbang mode.")

        # # #

        cs_n = Signal(reset=1)
        clk = Signal()
        dq_oe = Signal()
        wbone_width = len(bus.dat_r)


        read_cmd_params = {
            4: (_format_cmd(_QIOFR, 4), 4*8),
            2: (_format_cmd(_DIOFR, 2), 2*8),
            1: (_format_cmd(_FAST_READ, 1), 1*8)
        }
        read_cmd, cmd_width = read_cmd_params[spi_width]
        addr_width = 24

        dq = TSTriple(spi_width)
        # Keep DQ2,DQ3 as outputs during bitbang, this ensures they activate ~WP or ~HOLD functions
        self.specials.dq0 = Tristate(pads.dq[0], o=dq.o[0], i=dq.i[0], oe=dq.oe)
        self.specials.dq1 = Tristate(pads.dq[1], o=dq.o[1], i=dq.i[1], oe=dq.oe)
        self.specials.dq2 = Tristate(pads.dq[2], o=dq.o[2], i=dq.i[2], oe=(dq.oe | self.bitbang_en.storage))
        self.specials.dq3 = Tristate(pads.dq[3], o=dq.o[3], i=dq.i[3], oe=(dq.oe | self.bitbang_en.storage))

        sr = Signal(max(cmd_width, addr_width, wbone_width))
        if endianness == "big":
            self.comb += bus.dat_r.eq(sr)
        else:
            self.comb += bus.dat_r.eq(reverse_bytes(sr))

        hw_read_logic = [
            pads.clk.eq(clk),
            pads.cs_n.eq(cs_n),
            dq.o.eq(sr[-spi_width:]),
            dq.oe.eq(dq_oe)
        ]

        if with_bitbang:
            bitbang_logic = [
                pads.clk.eq(self.bitbang.storage[1]),
                pads.cs_n.eq(self.bitbang.storage[2]),

                # In Dual/Quad mode, no single data pin is consistently
                # an input or output thanks to dual/quad reads, so we need a bit
                # to swap direction of the pins. Aside from this additional bit,
                # bitbang mode is identical for Single/Dual/Quad; dq[0] is mosi
                # and dq[1] is miso, meaning remaining data pin values don't
                # appear in CSR registers.
                If(self.bitbang.storage[3],
                    dq.oe.eq(0)
                ).Else(
                    dq.oe.eq(1)
                ),
                If(self.bitbang.storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
                    self.miso.status.eq(dq.i[1])
                ),
                dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))
            ]

            self.comb += [
                If(self.bitbang_en.storage,
                    bitbang_logic
                ).Else(
                    hw_read_logic
                )
            ]

        else:
            self.comb += hw_read_logic

        if div < 2:
            raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
        else:
            i = Signal(max=div)
            dqi = Signal(spi_width)
            self.sync += [
                If(i == div//2 - 1,
                    clk.eq(1),
                    dqi.eq(dq.i),
                ),
                If(i == div - 1,
                    i.eq(0),
                    clk.eq(0),
                    sr.eq(Cat(dqi, sr[:-spi_width]))
                ).Else(
                    i.eq(i + 1),
                ),
            ]

        # spi is byte-addressed, prefix by zeros
        z = Replicate(0, log2_int(wbone_width//8))

        seq = [
            (cmd_width//spi_width*div,
                [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]),
            (addr_width//spi_width*div,
                [sr[-addr_width:].eq(Cat(z, bus.adr))]),
            ((dummy + wbone_width//spi_width)*div,
                [dq_oe.eq(0)]),
            (1,
                [bus.ack.eq(1), cs_n.eq(1)]),
            (div, # tSHSL!
                [bus.ack.eq(0)]),
            (0,
                []),
        ]

        # accumulate timeline deltas
        t, tseq = 0, []
        for dt, a in seq:
            tseq.append((t, a))
            t += dt

        self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq)
Example #6
0
    def __init__(self, pads):
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        databits = len(pads.dq)

        self.settings = sdram_settings.PhySettings(memtype="SDR",
                                                   dfi_databits=databits,
                                                   nphases=1,
                                                   rdphase=0,
                                                   wrphase=0,
                                                   rdcmdphase=0,
                                                   wrcmdphase=0,
                                                   cl=2,
                                                   read_latency=4,
                                                   write_latency=0)

        self.dfi = Interface(addressbits, bankbits, databits)

        ###

        #
        # Command/address
        #
        self.sync += [
            pads.a.eq(self.dfi.p0.address),
            pads.ba.eq(self.dfi.p0.bank),
            pads.cke.eq(self.dfi.p0.cke),
            pads.cas_n.eq(self.dfi.p0.cas_n),
            pads.ras_n.eq(self.dfi.p0.ras_n),
            pads.we_n.eq(self.dfi.p0.we_n)
        ]
        if hasattr(pads, "cs_n"):
            self.sync += pads.cs_n.eq(self.dfi.p0.cs_n)

        #
        # DQ/DQS/DM data
        #
        sd_dq_out = Signal(databits)
        drive_dq = Signal()
        self.sync += sd_dq_out.eq(self.dfi.p0.wrdata)
        self.specials += Tristate(pads.dq, sd_dq_out, drive_dq)
        self.sync += \
            If(self.dfi.p0.wrdata_en,
                pads.dm.eq(self.dfi.p0.wrdata_mask)
            ).Else(
                pads.dm.eq(0)
            )
        sd_dq_in_ps = Signal(databits)
        self.sync.sys_ps += sd_dq_in_ps.eq(pads.dq)
        self.sync += self.dfi.p0.rddata.eq(sd_dq_in_ps)

        #
        # DQ/DM control
        #
        d_dfi_wrdata_en = Signal()
        self.sync += d_dfi_wrdata_en.eq(self.dfi.p0.wrdata_en)
        self.comb += drive_dq.eq(d_dfi_wrdata_en)

        rddata_sr = Signal(4)
        self.comb += self.dfi.p0.rddata_valid.eq(rddata_sr[3])
        self.sync += rddata_sr.eq(Cat(self.dfi.p0.rddata_en, rddata_sr[:3]))
Example #7
0
    def __init__(self,
                 pads,
                 clk_freq,
                 fifo_depth=32,
                 read_time=128,
                 write_time=128):
        dw = len(pads.data)

        # read fifo (FTDI --> SoC)
        read_fifo = ClockDomainsRenamer({
            "write": "usb",
            "read": "sys"
        })(stream.AsyncFIFO(phy_description(dw), fifo_depth))
        read_buffer = ClockDomainsRenamer("usb")(stream.SyncFIFO(
            phy_description(dw), 4))
        self.comb += read_buffer.source.connect(read_fifo.sink)

        # write fifo (SoC --> FTDI)
        write_fifo = ClockDomainsRenamer({
            "write": "sys",
            "read": "usb"
        })(stream.AsyncFIFO(phy_description(dw), fifo_depth))

        self.submodules += read_fifo, read_buffer, write_fifo

        # sink / source interfaces
        self.sink = write_fifo.sink
        self.source = read_fifo.source

        # read / write arbitration
        wants_write = Signal()
        wants_read = Signal()

        txe_n = Signal()
        rxf_n = Signal()

        self.comb += [
            txe_n.eq(pads.txe_n),
            rxf_n.eq(pads.rxf_n),
            wants_write.eq(~txe_n & write_fifo.source.valid),
            wants_read.eq(~rxf_n & read_fifo.sink.ready),
        ]

        read_time_en, max_read_time = anti_starvation(self, read_time)
        write_time_en, max_write_time = anti_starvation(self, write_time)

        data_w_accepted = Signal(reset=1)

        fsm = FSM(reset_state="READ")
        self.submodules += ClockDomainsRenamer("usb")(fsm)

        fsm.act(
            "READ", read_time_en.eq(1),
            If(wants_write, If(~wants_read | max_read_time, NextState("RTW"))))
        fsm.act("RTW", NextState("WRITE"))
        fsm.act(
            "WRITE", write_time_en.eq(1),
            If(wants_read, If(~wants_write | max_write_time,
                              NextState("WTR"))),
            write_fifo.source.ready.eq(wants_write & data_w_accepted))
        fsm.act("WTR", NextState("READ"))

        # databus tristate
        data_w = Signal(dw)
        data_r = Signal(dw)
        data_oe = Signal()
        self.specials += Tristate(pads.data, data_w, data_oe, data_r)

        # read / write actions
        pads.oe_n.reset = 1
        pads.rd_n.reset = 1
        pads.wr_n.reset = 1

        self.sync.usb += [
            If(fsm.ongoing("READ"), data_oe.eq(0), pads.oe_n.eq(0),
               pads.rd_n.eq(~wants_read),
               pads.wr_n.eq(1)).Elif(fsm.ongoing("WRITE"), data_oe.eq(1),
                                     pads.oe_n.eq(1), pads.rd_n.eq(1),
                                     pads.wr_n.eq(~wants_write),
                                     data_w_accepted.eq(~txe_n)).Else(
                                         data_oe.eq(1),
                                         pads.oe_n.eq(~fsm.ongoing("WTR")),
                                         pads.rd_n.eq(1), pads.wr_n.eq(1)),
            read_buffer.sink.valid.eq(~pads.rd_n & ~rxf_n),
            read_buffer.sink.data.eq(data_r),
            If(~txe_n & data_w_accepted, data_w.eq(write_fifo.source.data))
        ]
Example #8
0
    def __init__(self, pads, sys_clk_freq=100e6):
        pads = PHYPadsCombiner(pads)
        memtype = "DDR3"
        tck = 2 / (2 * 2 * sys_clk_freq)
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        nphases = 2
        assert databits % 8 == 0

        # Init -------------------------------------------------------------------------------------
        self.submodules.init = ClockDomainsRenamer("init")(
            ECP5DDRPHYInit("sys2x"))

        # Parameters -------------------------------------------------------------------------------
        cl, cwl = get_cl_cw(memtype, tck)
        cl_sys_latency = get_sys_latency(nphases, cl)
        cwl_sys_latency = get_sys_latency(nphases, cwl)

        # Registers --------------------------------------------------------------------------------
        self._dly_sel = CSRStorage(databits // 8)

        self._rdly_dq_rst = CSR()
        self._rdly_dq_inc = CSR()
        self._rdly_dq_bitslip_rst = CSR()
        self._rdly_dq_bitslip = CSR()

        self._burstdet_clr = CSR()
        self._burstdet_seen = CSRStatus(databits // 8)

        # Observation
        self.datavalid = Signal(databits // 8)

        # PHY settings -----------------------------------------------------------------------------
        rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
        wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
        self.settings = PhySettings(phytype="ECP5DDRPHY",
                                    memtype=memtype,
                                    databits=databits,
                                    dfi_databits=4 * databits,
                                    nranks=nranks,
                                    nphases=nphases,
                                    rdphase=rdphase,
                                    wrphase=wrphase,
                                    rdcmdphase=rdcmdphase,
                                    wrcmdphase=wrcmdphase,
                                    cl=cl,
                                    cwl=cwl,
                                    read_latency=2 + cl_sys_latency + 2 +
                                    log2_int(4 // nphases) + 4,
                                    write_latency=cwl_sys_latency)

        # DFI Interface ----------------------------------------------------------------------------
        self.dfi = dfi = Interface(addressbits, bankbits, nranks, 4 * databits,
                                   4)

        # # #

        bl8_chunk = Signal()
        rddata_en = Signal(self.settings.read_latency)

        # Iterate on pads groups -------------------------------------------------------------------
        for pads_group in range(len(pads.groups)):
            pads.sel_group(pads_group)

            # Clock --------------------------------------------------------------------------------
            for i in range(len(pads.clk_p)):
                sd_clk_se = Signal()
                self.specials += Instance("ODDRX2F",
                                          i_RST=ResetSignal("sys2x"),
                                          i_ECLK=ClockSignal("sys2x"),
                                          i_SCLK=ClockSignal(),
                                          i_D0=0,
                                          i_D1=1,
                                          i_D2=0,
                                          i_D3=1,
                                          o_Q=pads.clk_p[i])

            # Addresses and Commands ---------------------------------------------------------------
            for i in range(addressbits):
                self.specials += Instance("ODDRX2F",
                                          i_RST=ResetSignal("sys2x"),
                                          i_ECLK=ClockSignal("sys2x"),
                                          i_SCLK=ClockSignal(),
                                          i_D0=dfi.phases[0].address[i],
                                          i_D1=dfi.phases[0].address[i],
                                          i_D2=dfi.phases[1].address[i],
                                          i_D3=dfi.phases[1].address[i],
                                          o_Q=pads.a[i])
            for i in range(bankbits):
                self.specials += Instance("ODDRX2F",
                                          i_RST=ResetSignal("sys2x"),
                                          i_ECLK=ClockSignal("sys2x"),
                                          i_SCLK=ClockSignal(),
                                          i_D0=dfi.phases[0].bank[i],
                                          i_D1=dfi.phases[0].bank[i],
                                          i_D2=dfi.phases[1].bank[i],
                                          i_D3=dfi.phases[1].bank[i],
                                          o_Q=pads.ba[i])
            controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
            if hasattr(pads, "reset_n"):
                controls.append("reset_n")
            if hasattr(pads, "cs_n"):
                controls.append("cs_n")
            for name in controls:
                for i in range(len(getattr(pads, name))):
                    self.specials += Instance(
                        "ODDRX2F",
                        i_RST=ResetSignal("sys2x"),
                        i_ECLK=ClockSignal("sys2x"),
                        i_SCLK=ClockSignal(),
                        i_D0=getattr(dfi.phases[0], name)[i],
                        i_D1=getattr(dfi.phases[0], name)[i],
                        i_D2=getattr(dfi.phases[1], name)[i],
                        i_D3=getattr(dfi.phases[1], name)[i],
                        o_Q=getattr(pads, name)[i])

        # DQ ---------------------------------------------------------------------------------------
        dq_oe = Signal()
        dqs_oe = Signal()
        dqs_pattern = DQSPattern()
        self.submodules += dqs_pattern
        for i in range(databits // 8):
            # DQSBUFM
            dqs_i = Signal()
            dqsr90 = Signal()
            dqsw270 = Signal()
            dqsw = Signal()
            rdpntr = Signal(3)
            wrpntr = Signal(3)
            rdly = Signal(7)
            self.sync += \
                If(self._dly_sel.storage[i],
                    If(self._rdly_dq_rst.re,
                        rdly.eq(0),
                    ).Elif(self._rdly_dq_inc.re,
                        rdly.eq(rdly + 1),
                    )
                )
            datavalid = Signal()
            burstdet = Signal()
            dqs_read = Signal()
            dqs_bitslip = Signal(2)
            self.sync += [
                If(
                    self._dly_sel.storage[i],
                    If(self._rdly_dq_bitslip_rst.re, dqs_bitslip.eq(0)).Elif(
                        self._rdly_dq_bitslip.re,
                        dqs_bitslip.eq(dqs_bitslip + 1)))
            ]
            dqs_cases = {}
            for j, b in enumerate(range(-2, 2)):
                dqs_cases[j] = dqs_read.eq(
                    rddata_en[cl_sys_latency + b:cl_sys_latency + b + 2] != 0)
            self.sync += Case(dqs_bitslip, dqs_cases)
            self.specials += Instance(
                "DQSBUFM",
                p_DQS_LI_DEL_ADJ="MINUS",
                p_DQS_LI_DEL_VAL=1,
                p_DQS_LO_DEL_ADJ="MINUS",
                p_DQS_LO_DEL_VAL=4,
                # Clocks / Reset
                i_SCLK=ClockSignal("sys"),
                i_ECLK=ClockSignal("sys2x"),
                i_RST=ResetSignal("sys2x"),
                i_DDRDEL=self.init.delay,
                i_PAUSE=self.init.pause | self._dly_sel.storage[i],

                # Control
                # Assert LOADNs to use DDRDEL control
                i_RDLOADN=0,
                i_RDMOVE=0,
                i_RDDIRECTION=1,
                i_WRLOADN=0,
                i_WRMOVE=0,
                i_WRDIRECTION=1,

                # Reads (generate shifted DQS clock for reads)
                i_READ0=dqs_read,
                i_READ1=dqs_read,
                i_READCLKSEL0=rdly[0],
                i_READCLKSEL1=rdly[1],
                i_READCLKSEL2=rdly[2],
                i_DQSI=dqs_i,
                o_DQSR90=dqsr90,
                o_RDPNTR0=rdpntr[0],
                o_RDPNTR1=rdpntr[1],
                o_RDPNTR2=rdpntr[2],
                o_WRPNTR0=wrpntr[0],
                o_WRPNTR1=wrpntr[1],
                o_WRPNTR2=wrpntr[2],
                o_DATAVALID=self.datavalid[i],
                o_BURSTDET=burstdet,

                # Writes (generate shifted ECLK clock for writes)
                o_DQSW270=dqsw270,
                o_DQSW=dqsw)
            burstdet_d = Signal()
            self.sync += [
                burstdet_d.eq(burstdet),
                If(self._burstdet_clr.re, self._burstdet_seen.status[i].eq(0)),
                If(burstdet & ~burstdet_d,
                   self._burstdet_seen.status[i].eq(1)),
            ]

            # DQS and DM ---------------------------------------------------------------------------
            dm_o_data = Signal(8)
            dm_o_data_d = Signal(8)
            dm_o_data_muxed = Signal(4)
            self.comb += dm_o_data.eq(
                Cat(dfi.phases[0].wrdata_mask[0 * databits // 8 + i],
                    dfi.phases[0].wrdata_mask[1 * databits // 8 + i],
                    dfi.phases[0].wrdata_mask[2 * databits // 8 + i],
                    dfi.phases[0].wrdata_mask[3 * databits // 8 + i],
                    dfi.phases[1].wrdata_mask[0 * databits // 8 + i],
                    dfi.phases[1].wrdata_mask[1 * databits // 8 + i],
                    dfi.phases[1].wrdata_mask[2 * databits // 8 + i],
                    dfi.phases[1].wrdata_mask[3 * databits // 8 + i]), )
            self.sync += dm_o_data_d.eq(dm_o_data)
            dm_bl8_cases = {}
            dm_bl8_cases[0] = dm_o_data_muxed.eq(dm_o_data[:4])
            dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:])
            self.sync += Case(bl8_chunk, dm_bl8_cases)  # FIXME: use self.comb?
            self.specials += Instance("ODDRX2DQA",
                                      i_RST=ResetSignal("sys2x"),
                                      i_ECLK=ClockSignal("sys2x"),
                                      i_SCLK=ClockSignal(),
                                      i_DQSW270=dqsw270,
                                      i_D0=dm_o_data_muxed[0],
                                      i_D1=dm_o_data_muxed[1],
                                      i_D2=dm_o_data_muxed[2],
                                      i_D3=dm_o_data_muxed[3],
                                      o_Q=pads.dm[i])

            dqs = Signal()
            dqs_oe_n = Signal()
            self.specials += [
                Instance(
                    "ODDRX2DQSB",
                    i_RST=ResetSignal("sys2x"),
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    i_DQSW=dqsw,
                    i_D0=0,  # FIXME: dqs_pattern.o[3],
                    i_D1=1,  # FIXME: dqs_pattern.o[2],
                    i_D2=0,  # FIXME: dqs_pattern.o[1],
                    i_D3=1,  # FIXME: dqs_pattern.o[0],
                    o_Q=dqs),
                Instance("TSHX2DQSA",
                         i_RST=ResetSignal("sys2x"),
                         i_ECLK=ClockSignal("sys2x"),
                         i_SCLK=ClockSignal(),
                         i_DQSW=dqsw,
                         i_T0=~(dqs_pattern.preamble | dqs_oe
                                | dqs_pattern.postamble),
                         i_T1=~(dqs_pattern.preamble | dqs_oe
                                | dqs_pattern.postamble),
                         o_Q=dqs_oe_n),
                Tristate(pads.dqs_p[i], dqs, ~dqs_oe_n, dqs_i)
            ]

            for j in range(8 * i, 8 * (i + 1)):
                dq_o = Signal()
                dq_i = Signal()
                dq_oe_n = Signal()
                dq_i_delayed = Signal()
                dq_i_data = Signal(8)
                dq_o_data = Signal(8)
                dq_o_data_d = Signal(8)
                dq_o_data_muxed = Signal(4)
                self.comb += dq_o_data.eq(
                    Cat(dfi.phases[0].wrdata[0 * databits + j],
                        dfi.phases[0].wrdata[1 * databits + j],
                        dfi.phases[0].wrdata[2 * databits + j],
                        dfi.phases[0].wrdata[3 * databits + j],
                        dfi.phases[1].wrdata[0 * databits + j],
                        dfi.phases[1].wrdata[1 * databits + j],
                        dfi.phases[1].wrdata[2 * databits + j],
                        dfi.phases[1].wrdata[3 * databits + j]))
                self.sync += dq_o_data_d.eq(dq_o_data)
                dq_bl8_cases = {}
                dq_bl8_cases[0] = dq_o_data_muxed.eq(dq_o_data[:4])
                dq_bl8_cases[1] = dq_o_data_muxed.eq(dq_o_data_d[4:])
                self.sync += Case(bl8_chunk,
                                  dq_bl8_cases)  # FIXME: use self.comb?
                _dq_i_data = Signal(4)
                self.specials += [
                    Instance("ODDRX2DQA",
                             i_RST=ResetSignal("sys2x"),
                             i_ECLK=ClockSignal("sys2x"),
                             i_SCLK=ClockSignal(),
                             i_DQSW270=dqsw270,
                             i_D0=dq_o_data_muxed[0],
                             i_D1=dq_o_data_muxed[1],
                             i_D2=dq_o_data_muxed[2],
                             i_D3=dq_o_data_muxed[3],
                             o_Q=dq_o),
                    Instance("DELAYF",
                             p_DEL_MODE="DQS_ALIGNED_X2",
                             i_LOADN=1,
                             i_MOVE=0,
                             i_DIRECTION=0,
                             i_A=dq_i,
                             o_Z=dq_i_delayed),
                    Instance(
                        "IDDRX2DQA",
                        i_RST=ResetSignal("sys2x"),
                        i_ECLK=ClockSignal("sys2x"),
                        i_SCLK=ClockSignal(),
                        i_DQSR90=dqsr90,
                        i_RDPNTR0=rdpntr[0],
                        i_RDPNTR1=rdpntr[1],
                        i_RDPNTR2=rdpntr[2],
                        i_WRPNTR0=wrpntr[0],
                        i_WRPNTR1=wrpntr[1],
                        i_WRPNTR2=wrpntr[2],
                        i_D=dq_i_delayed,
                        o_Q0=_dq_i_data[0],
                        o_Q1=_dq_i_data[1],
                        o_Q2=_dq_i_data[2],
                        o_Q3=_dq_i_data[3],
                    )
                ]
                self.sync += dq_i_data[:4].eq(dq_i_data[4:])
                self.sync += dq_i_data[4:].eq(_dq_i_data)
                self.comb += [
                    dfi.phases[0].rddata[0 * databits + j].eq(dq_i_data[0]),
                    dfi.phases[0].rddata[1 * databits + j].eq(dq_i_data[1]),
                    dfi.phases[0].rddata[2 * databits + j].eq(dq_i_data[2]),
                    dfi.phases[0].rddata[3 * databits + j].eq(dq_i_data[3]),
                    dfi.phases[1].rddata[0 * databits + j].eq(dq_i_data[4]),
                    dfi.phases[1].rddata[1 * databits + j].eq(dq_i_data[5]),
                    dfi.phases[1].rddata[2 * databits + j].eq(dq_i_data[6]),
                    dfi.phases[1].rddata[3 * databits + j].eq(dq_i_data[7]),
                ]
                self.specials += [
                    Instance(
                        "TSHX2DQA",
                        i_RST=ResetSignal("sys2x"),
                        i_ECLK=ClockSignal("sys2x"),
                        i_SCLK=ClockSignal(),
                        i_DQSW270=dqsw270,
                        i_T0=~(dqs_pattern.preamble | dq_oe
                               | dqs_pattern.postamble),
                        i_T1=~(dqs_pattern.preamble | dq_oe
                               | dqs_pattern.postamble),
                        o_Q=dq_oe_n,
                    ),
                    Tristate(pads.dq[j], dq_o, ~dq_oe_n, dq_i)
                ]

        # Read Control Path ------------------------------------------------------------------------
        # Creates a shift register of read commands coming from the DFI interface. This shift register
        # is used to control DQS read (internal read pulse of the DQSBUF) and to indicate to the
        # DFI interface that the read data is valid.
        #
        # The DQS read must be asserted for 2 sys_clk cycles before the read data is coming back from
        # the DRAM (see 6.2.4 READ Pulse Positioning Optimization of FPGA-TN-02035-1.2)
        #
        # The read data valid is asserted for 1 sys_clk cycle when the data is available on the DFI
        # interface, the latency is the sum of the ODDRX2DQA, CAS, IDDRX2DQA latencies.
        rddata_en_last = Signal.like(rddata_en)
        self.comb += rddata_en.eq(
            Cat(dfi.phases[self.settings.rdphase].rddata_en, rddata_en_last))
        self.sync += rddata_en_last.eq(rddata_en)
        self.sync += [
            phase.rddata_valid.eq(rddata_en[-1]) for phase in dfi.phases
        ]

        # Write Control Path -----------------------------------------------------------------------
        # Creates a shift register of write commands coming from the DFI interface. This shift register
        # is used to control DQ/DQS tristates and to select write data of the DRAM burst from the DFI
        # interface: The PHY is operating in halfrate mode (so provide 4 datas every sys_clk cycles:
        # 2x for DDR, 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency.
        # Writes are then performed in 2 sys_clk cycles and data needs to be selected for each cycle.
        # FIXME: understand +2
        wrdata_en = Signal(cwl_sys_latency + 5)
        wrdata_en_last = Signal.like(wrdata_en)
        self.comb += wrdata_en.eq(
            Cat(dfi.phases[self.settings.wrphase].wrdata_en, wrdata_en_last))
        self.sync += wrdata_en_last.eq(wrdata_en)
        self.comb += dq_oe.eq(wrdata_en[cwl_sys_latency + 2]
                              | wrdata_en[cwl_sys_latency + 3])
        self.comb += bl8_chunk.eq(wrdata_en[cwl_sys_latency + 1])
        self.comb += dqs_oe.eq(dq_oe)

        # Write DQS Postamble/Preamble Control Path ------------------------------------------------
        # Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last
        # write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles:
        # 1 for Preamble, 2 for the Write and 1 for the Postamble.
        self.comb += dqs_pattern.preamble.eq(wrdata_en[cwl_sys_latency + 1]
                                             & ~wrdata_en[cwl_sys_latency + 2])
        self.comb += dqs_pattern.postamble.eq(
            wrdata_en[cwl_sys_latency + 4] & ~wrdata_en[cwl_sys_latency + 3])
Example #9
0
    def __init__(self, pads, default=_default_edid):
        self._hpd_notif = CSRStatus()
        self._hpd_en = CSRStorage()
        self.specials.mem = Memory(8, 128, init=default)

        ###

        # HPD
        if hasattr(pads, "hpd_notif"):
            self.specials += MultiReg(pads.hpd_notif, self._hpd_notif.status)
        else:
            self.comb += self._hpd_notif.status.eq(1)
        if hasattr(pads, "hpd_en"):
            self.comb += pads.hpd_en.eq(self._hpd_en.storage)

        # EDID
        scl_raw = Signal()
        sda_i = Signal()
        sda_raw = Signal()
        sda_drv = Signal()
        _sda_drv_reg = Signal()
        _sda_i_async = Signal()
        self.sync += _sda_drv_reg.eq(sda_drv)
        self.specials += [
            MultiReg(pads.scl, scl_raw),
            Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
            MultiReg(_sda_i_async, sda_raw)
        ]

        # for debug
        self.scl = scl_raw
        self.sda_i = sda_i
        self.sda_o = Signal()
        self.comb += self.sda_o.eq(~_sda_drv_reg)
        self.sda_oe = _sda_drv_reg

        scl_i = Signal()
        samp_count = Signal(6)
        samp_carry = Signal()
        self.sync += [
            Cat(samp_count, samp_carry).eq(samp_count + 1),
            If(samp_carry,
                scl_i.eq(scl_raw),
                sda_i.eq(sda_raw)
            )
        ]

        scl_r = Signal()
        sda_r = Signal()
        scl_rising = Signal()
        sda_rising = Signal()
        sda_falling = Signal()
        self.sync += [
            scl_r.eq(scl_i),
            sda_r.eq(sda_i)
        ]
        self.comb += [
            scl_rising.eq(scl_i & ~scl_r),
            sda_rising.eq(sda_i & ~sda_r),
            sda_falling.eq(~sda_i & sda_r)
        ]

        start = Signal()
        self.comb += start.eq(scl_i & sda_falling)

        din = Signal(8)
        counter = Signal(max=9)
        self.sync += [
            If(start, counter.eq(0)),
            If(scl_rising,
                If(counter == 8,
                    counter.eq(0)
                ).Else(
                    counter.eq(counter + 1),
                    din.eq(Cat(sda_i, din[:7]))
                )
            )
        ]

        self.din = din
        self.counter = counter

        is_read = Signal()
        update_is_read = Signal()
        self.sync += If(update_is_read, is_read.eq(din[0]))

        offset_counter = Signal(max=128)
        oc_load = Signal()
        oc_inc = Signal()
        self.sync += [
            If(oc_load,
                offset_counter.eq(din)
            ).Elif(oc_inc,
                offset_counter.eq(offset_counter + 1)
            )
        ]
        rdport = self.mem.get_port()
        self.specials += rdport
        self.comb += rdport.adr.eq(offset_counter)
        data_bit = Signal()

        zero_drv = Signal()
        data_drv = Signal()
        self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit))

        data_drv_en = Signal()
        data_drv_stop = Signal()
        self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
        self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))

        self.submodules.fsm = fsm = FSM()

        fsm.act("WAIT_START")
        fsm.act("RCV_ADDRESS",
            If(counter == 8,
                If(din[1:] == 0x50,
                    update_is_read.eq(1),
                    NextState("ACK_ADDRESS0")
                ).Else(
                    NextState("WAIT_START")
                )
            )
        )
        fsm.act("ACK_ADDRESS0",
            If(~scl_i, NextState("ACK_ADDRESS1"))
        )
        fsm.act("ACK_ADDRESS1",
            zero_drv.eq(1),
            If(scl_i, NextState("ACK_ADDRESS2"))
        )
        fsm.act("ACK_ADDRESS2",
            zero_drv.eq(1),
            If(~scl_i,
                If(is_read,
                    NextState("READ")
                ).Else(
                    NextState("RCV_OFFSET")
                )
            )
        )

        fsm.act("RCV_OFFSET",
            If(counter == 8,
                oc_load.eq(1),
                NextState("ACK_OFFSET0")
            )
        )
        fsm.act("ACK_OFFSET0",
            If(~scl_i, NextState("ACK_OFFSET1"))
        )
        fsm.act("ACK_OFFSET1",
            zero_drv.eq(1),
            If(scl_i, NextState("ACK_OFFSET2"))
        )
        fsm.act("ACK_OFFSET2",
            zero_drv.eq(1),
            If(~scl_i, NextState("RCV_ADDRESS"))
        )

        fsm.act("READ",
            If(~scl_i,
                If(counter == 8,
                    data_drv_stop.eq(1),
                    NextState("ACK_READ")
                ).Else(
                    data_drv_en.eq(1)
                )
            )
        )
        fsm.act("ACK_READ",
            If(scl_rising,
                oc_inc.eq(1),
                If(sda_i,
                    NextState("WAIT_START")
                ).Else(
                    NextState("READ")
                )
            )
        )

        for state in fsm.actions.keys():
            fsm.act(state, If(start, NextState("RCV_ADDRESS")))
            fsm.act(state, If(~self._hpd_en.storage, NextState("WAIT_START")))
Example #10
0
    def __init__(self,
                 pads,
                 clk_freq,
                 fifo_depth=32,
                 read_time=128,
                 write_time=128):
        dw = len(pads.data)
        self.clk_freq = clk_freq

        # timings
        tRD = self.ns(30)  # RD# active pulse width (t4)
        tRDDataSetup = self.ns(14)  # RD# to DATA (t3)
        tWRDataSetup = self.ns(5)  # DATA to WR# active setup time (t8)
        tWR = self.ns(30)  # WR# active pulse width (t10)
        tMultiReg = 2

        # read fifo (FTDI --> SoC)
        read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth)

        # write fifo (SoC --> FTDI)
        write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth)

        self.submodules += read_fifo, write_fifo

        # sink / source interfaces
        self.sink = write_fifo.sink
        self.source = read_fifo.source

        # read / write arbitration
        wants_write = Signal()
        wants_read = Signal()

        txe_n = Signal()
        rxf_n = Signal()

        self.specials += [
            MultiReg(pads.txe_n, txe_n),
            MultiReg(pads.rxf_n, rxf_n)
        ]

        self.comb += [
            wants_write.eq(~txe_n & write_fifo.source.valid),
            wants_read.eq(~rxf_n & read_fifo.sink.ready),
        ]

        read_time_en, max_read_time = anti_starvation(self, read_time)
        write_time_en, max_write_time = anti_starvation(self, write_time)

        fsm = FSM(reset_state="READ")
        self.submodules += fsm

        read_done = Signal()
        write_done = Signal()
        commuting = Signal()

        fsm.act(
            "READ", read_time_en.eq(1),
            If(
                wants_write & read_done,
                If(~wants_read | max_read_time, commuting.eq(1),
                   NextState("RTW"))))
        fsm.act("RTW", NextState("WRITE"))
        fsm.act(
            "WRITE", write_time_en.eq(1),
            If(
                wants_read & write_done,
                If(~wants_write | max_write_time, commuting.eq(1),
                   NextState("WTR"))))
        fsm.act("WTR", NextState("READ"))

        # databus tristate
        data_w = Signal(dw)
        data_r_async = Signal(dw)
        data_r = Signal(dw)
        data_oe = Signal()
        self.specials += [
            Tristate(pads.data, data_w, data_oe, data_r_async),
            MultiReg(data_r_async, data_r)
        ]

        # read actions
        pads.rd_n.reset = 1

        read_fsm = FSM(reset_state="IDLE")
        self.submodules += read_fsm
        read_counter = Signal(8)
        read_counter_reset = Signal()
        read_counter_ce = Signal()
        self.sync += \
            If(read_counter_reset,
                read_counter.eq(0)
            ).Elif(read_counter_ce,
                read_counter.eq(read_counter + 1)
            )

        read_fsm.act(
            "IDLE", read_done.eq(1), read_counter_reset.eq(1),
            If(
                fsm.ongoing("READ") & wants_read,
                If(~commuting, NextState("PULSE_RD_N"))))
        read_fsm.act(
            "PULSE_RD_N", pads.rd_n.eq(0), read_counter_ce.eq(1),
            If(read_counter == max((tRD - 1), (tRDDataSetup + tMultiReg - 1)),
               NextState("ACQUIRE_DATA")))
        read_fsm.act("ACQUIRE_DATA", read_fifo.sink.valid.eq(1),
                     read_fifo.sink.data.eq(data_r), NextState("WAIT_RXF_N"))
        read_fsm.act("WAIT_RXF_N", If(rxf_n, NextState("IDLE")))

        # write actions
        pads.wr_n.reset = 1

        write_fsm = FSM(reset_state="IDLE")
        self.submodules += write_fsm
        write_counter = Signal(8)
        write_counter_reset = Signal()
        write_counter_ce = Signal()
        self.sync += \
            If(write_counter_reset,
                write_counter.eq(0)
            ).Elif(write_counter_ce,
                write_counter.eq(write_counter + 1)
            )

        write_fsm.act(
            "IDLE", write_done.eq(1), write_counter_reset.eq(1),
            If(
                fsm.ongoing("WRITE") & wants_write,
                If(~commuting, NextState("SET_DATA"))))
        write_fsm.act(
            "SET_DATA", data_oe.eq(1), data_w.eq(write_fifo.source.data),
            write_counter_ce.eq(1),
            If(write_counter == (tWRDataSetup - 1), write_counter_reset.eq(1),
               NextState("PULSE_WR_N")))
        write_fsm.act("PULSE_WR_N", data_oe.eq(1),
                      data_w.eq(write_fifo.source.data), pads.wr_n.eq(0),
                      write_counter_ce.eq(1),
                      If(write_counter == (tWR - 1), NextState("WAIT_TXE_N")))
        write_fsm.act(
            "WAIT_TXE_N",
            If(txe_n, write_fifo.source.ready.eq(1), NextState("IDLE")))
    def __init__(self,
                 platform,
                 usb_connector=0,
                 with_usb3=True,
                 with_usb3_analyzer=False):
        BaseSoC.__init__(self, platform)

        # fmc vadj (2.5V)
        self.comb += platform.request("vadj").eq(0b10)

        # usb ios
        usb_reset_n = platform.request("usb_reset_n", usb_connector)
        if with_usb3:
            usb_pipe_ctrl = platform.request("usb_pipe_ctrl", usb_connector)
            usb_pipe_status = platform.request("usb_pipe_status",
                                               usb_connector)
            usb_pipe_data = platform.request("usb_pipe_data", usb_connector)

        usb3_reset_n = Signal(reset=1)
        self.comb += usb_reset_n.eq(usb3_reset_n)

        # usb3 core
        if with_usb3:

            class USB3Control(Module, AutoCSR):
                def __init__(self):
                    self._phy_enable = CSRStorage()
                    self._core_enable = CSRStorage()

                    # probably not working but prevent synthesis optimizations
                    self._buf_in_addr = CSRStorage(9)
                    self._buf_in_data = CSRStorage(32)
                    self._buf_in_wren = CSR()
                    self._buf_in_request = CSRStatus()
                    self._buf_in_ready = CSRStatus()
                    self._buf_in_commit = CSR()
                    self._buf_in_commit_len = CSRStorage(11)
                    self._buf_in_commit_ack = CSRStatus()

                    self._buf_out_addr = CSRStorage(9)
                    self._buf_out_q = CSRStatus(32)
                    self._buf_out_len = CSRStatus(11)
                    self._buf_out_hasdata = CSRStatus()
                    self._buf_out_arm = CSR()
                    self._buf_out_arm_ack = CSRStatus()

                    # # #

                    self.phy_enable = self._phy_enable.storage
                    self.core_enable = self._core_enable.storage

                    self.buf_in_addr = self._buf_in_addr.storage
                    self.buf_in_data = self._buf_in_data.storage
                    self.buf_in_wren = self._buf_in_wren.re & self._buf_in_wren.r
                    self.buf_in_request = self._buf_in_request.status
                    self.buf_in_ready = self._buf_in_ready.status
                    self.buf_in_commit = self._buf_in_commit.re & self._buf_in_commit.r
                    self.buf_in_commit_len = self._buf_in_commit_len.storage
                    self.buf_in_commit_ack = self._buf_in_commit_ack.status

                    self.buf_out_addr = self._buf_out_addr.storage
                    self.buf_out_q = self._buf_out_q.status
                    self.buf_out_len = self._buf_out_len.status
                    self.buf_out_hasdata = self._buf_out_hasdata.status
                    self.buf_out_arm = self._buf_out_arm.re & self._buf_out_arm.r
                    self.buf_out_arm_ack = self._buf_out_arm_ack.status

            self.submodules.usb3_control = USB3Control()

            phy_pipe_pll_locked = Signal()
            phy_pipe_pll_fb = Signal()

            phy_pipe_half_clk_pll = Signal()
            phy_pipe_half_clk_phase_pll = Signal()
            phy_pipe_quarter_clk_pll = Signal()
            phy_pipe_tx_clk_phase_pll = Signal()

            phy_pipe_half_clk = Signal()
            phy_pipe_half_clk_phase = Signal()
            phy_pipe_quarter_clk = Signal()
            phy_pipe_tx_clk_phase = Signal()

            self.specials += [
                Instance(
                    "PLLE2_BASE",
                    p_STARTUP_WAIT="FALSE",
                    o_LOCKED=phy_pipe_pll_locked,

                    # VCO @ 1GHz
                    p_REF_JITTER1=0.01,
                    p_CLKIN1_PERIOD=4.0,
                    p_CLKFBOUT_MULT=4,
                    p_DIVCLK_DIVIDE=1,
                    i_CLKIN1=usb_pipe_data.rx_clk,
                    i_CLKFBIN=phy_pipe_pll_fb,
                    o_CLKFBOUT=phy_pipe_pll_fb,

                    # 125MHz: 1/2 PCLK
                    p_CLKOUT0_DIVIDE=8,
                    p_CLKOUT0_PHASE=0.0,
                    o_CLKOUT0=phy_pipe_half_clk_pll,

                    # 125MHz: 1/2 PCLK, phase shift 90
                    p_CLKOUT1_DIVIDE=8,
                    p_CLKOUT1_PHASE=90.0,
                    o_CLKOUT1=phy_pipe_half_clk_phase_pll,

                    # 62.5MHz: 1/4 PCLK
                    p_CLKOUT2_DIVIDE=16,
                    p_CLKOUT2_PHASE=0.0,
                    o_CLKOUT2=phy_pipe_quarter_clk_pll,

                    # 250Mhz: TX CLK, phase shift 90
                    p_CLKOUT3_DIVIDE=4,
                    p_CLKOUT3_PHASE=90.0,
                    o_CLKOUT3=phy_pipe_tx_clk_phase_pll),
                Instance("BUFG",
                         i_I=phy_pipe_half_clk_pll,
                         o_O=phy_pipe_half_clk),
                Instance("BUFG",
                         i_I=phy_pipe_half_clk_phase_pll,
                         o_O=phy_pipe_half_clk_phase),
                Instance("BUFG",
                         i_I=phy_pipe_quarter_clk_pll,
                         o_O=phy_pipe_quarter_clk),
                Instance("BUFG",
                         i_I=phy_pipe_tx_clk_phase_pll,
                         o_O=phy_pipe_tx_clk_phase),
            ]

            self.clock_domains.cd_phy_pipe_half = ClockDomain()
            self.clock_domains.cd_phy_pipe_half_phase = ClockDomain()
            self.clock_domains.cd_phy_pipe_quarter = ClockDomain()
            self.clock_domains.cd_phy_pipe_tx_phase = ClockDomain()
            self.comb += [
                self.cd_phy_pipe_half.clk.eq(phy_pipe_half_clk),
                self.cd_phy_pipe_half_phase.clk.eq(phy_pipe_half_clk_phase),
                self.cd_phy_pipe_quarter.clk.eq(phy_pipe_quarter_clk),
                self.cd_phy_pipe_tx_phase.clk.eq(phy_pipe_tx_clk_phase)
            ]
            self.specials += [
                AsyncResetSynchronizer(self.cd_phy_pipe_half,
                                       ~phy_pipe_pll_locked),
                AsyncResetSynchronizer(self.cd_phy_pipe_half_phase,
                                       ~phy_pipe_pll_locked),
                AsyncResetSynchronizer(self.cd_phy_pipe_quarter,
                                       ~phy_pipe_pll_locked),
                AsyncResetSynchronizer(self.cd_phy_pipe_tx_phase,
                                       ~phy_pipe_pll_locked)
            ]
            self.cd_phy_pipe_half.clk.attr.add("keep")
            self.cd_phy_pipe_half_phase.clk.attr.add("keep")
            self.cd_phy_pipe_quarter.clk.attr.add("keep")
            self.cd_phy_pipe_tx_phase.clk.attr.add("keep")
            self.platform.add_period_constraint(self.cd_phy_pipe_half.clk, 8.0)
            self.platform.add_period_constraint(
                self.cd_phy_pipe_half_phase.clk, 8.0)
            self.platform.add_period_constraint(self.cd_phy_pipe_quarter.clk,
                                                16.0)
            self.platform.add_period_constraint(self.cd_phy_pipe_tx_phase.clk,
                                                4.0)
            self.platform.add_false_path_constraints(
                self.crg.cd_sys.clk, self.cd_phy_pipe_half.clk,
                self.cd_phy_pipe_half_phase.clk, self.cd_phy_pipe_quarter.clk,
                self.cd_phy_pipe_tx_phase.clk)

            phy_pipe_rx_data = Signal(32)
            phy_pipe_rx_datak = Signal(4)
            phy_pipe_rx_valid = Signal(2)

            phy_pipe_tx_data = Signal(32)
            phy_pipe_tx_datak = Signal(4)

            phy_rx_status = Signal(6)
            phy_phy_status = Signal(2)

            dbg_pipe_state = Signal(6)
            dbg_ltssm_state = Signal(5)

            usb_pipe_status_phy_status = Signal()
            self.specials += Tristate(usb_pipe_status.phy_status, 0,
                                      ~usb3_reset_n,
                                      usb_pipe_status_phy_status)

            self.comb += usb3_reset_n.eq(self.usb3_control.phy_enable
                                         | platform.request("user_sw", 0))
            self.specials += Instance(
                "usb3_top",
                i_ext_clk=ClockSignal(),
                i_reset_n=self.usb3_control.core_enable
                | platform.request("user_sw", 1),
                i_phy_pipe_half_clk=ClockSignal("phy_pipe_half"),
                i_phy_pipe_half_clk_phase=ClockSignal("phy_pipe_half_phase"),
                i_phy_pipe_quarter_clk=ClockSignal("phy_pipe_quarter"),
                i_phy_pipe_rx_data=phy_pipe_rx_data,
                i_phy_pipe_rx_datak=phy_pipe_rx_datak,
                i_phy_pipe_rx_valid=phy_pipe_rx_valid,
                o_phy_pipe_tx_data=phy_pipe_tx_data,
                o_phy_pipe_tx_datak=phy_pipe_tx_datak,

                #o_phy_reset_n=,
                #o_phy_out_enable=,
                o_phy_phy_reset_n=usb_pipe_ctrl.phy_reset_n,
                o_phy_tx_detrx_lpbk=usb_pipe_ctrl.tx_detrx_lpbk,
                o_phy_tx_elecidle=usb_pipe_ctrl.tx_elecidle,
                io_phy_rx_elecidle=usb_pipe_status.rx_elecidle,
                i_phy_rx_status=phy_rx_status,
                o_phy_power_down=usb_pipe_ctrl.power_down,
                i_phy_phy_status_i=phy_phy_status,
                #o_phy_phy_status_o=,
                i_phy_pwrpresent=usb_pipe_status.pwr_present,
                o_phy_tx_oneszeros=usb_pipe_ctrl.tx_oneszeros,
                o_phy_tx_deemph=usb_pipe_ctrl.tx_deemph,
                o_phy_tx_margin=usb_pipe_ctrl.tx_margin,
                o_phy_tx_swing=usb_pipe_ctrl.tx_swing,
                o_phy_rx_polarity=usb_pipe_ctrl.rx_polarity,
                o_phy_rx_termination=usb_pipe_ctrl.rx_termination,
                o_phy_rate=usb_pipe_ctrl.rate,
                o_phy_elas_buf_mode=usb_pipe_ctrl.elas_buf_mode,
                i_buf_in_addr=self.usb3_control.buf_in_addr,
                i_buf_in_data=self.usb3_control.buf_in_data,
                i_buf_in_wren=self.usb3_control.buf_in_wren,
                o_buf_in_request=self.usb3_control.buf_in_request,
                o_buf_in_ready=self.usb3_control.buf_in_ready,
                i_buf_in_commit=self.usb3_control.buf_in_commit,
                i_buf_in_commit_len=self.usb3_control.buf_in_commit_len,
                o_buf_in_commit_ack=self.usb3_control.buf_in_commit_ack,
                i_buf_out_addr=self.usb3_control.buf_out_addr,
                o_buf_out_q=self.usb3_control.buf_out_q,
                o_buf_out_len=self.usb3_control.buf_out_len,
                o_buf_out_hasdata=self.usb3_control.buf_out_hasdata,
                i_buf_out_arm=self.usb3_control.buf_out_arm,
                o_buf_out_arm_ack=self.usb3_control.buf_out_arm_ack,

                #o_vend_req_act=,
                #o_vend_req_request=,
                #o_vend_req_val=,
                o_dbg_pipe_state=dbg_pipe_state,
                o_dbg_ltssm_state=dbg_ltssm_state)
            platform.add_verilog_include_path(os.path.join("core"))
            platform.add_verilog_include_path(os.path.join("core", "usb3"))
            platform.add_source_dir(os.path.join("core", "usb3"))

            # ddr inputs
            self.specials += Instance(
                "IDDR",
                p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
                i_C=ClockSignal("phy_pipe_half"),
                i_CE=1,
                i_S=0,
                i_R=0,
                i_D=usb_pipe_data.rx_valid,
                o_Q1=phy_pipe_rx_valid[0],
                o_Q2=phy_pipe_rx_valid[1],
            )
            for i in range(16):
                self.specials += Instance(
                    "IDDR",
                    p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
                    i_C=ClockSignal("phy_pipe_half"),
                    i_CE=1,
                    i_S=0,
                    i_R=0,
                    i_D=usb_pipe_data.rx_data[i],
                    o_Q1=phy_pipe_rx_data[i],
                    o_Q2=phy_pipe_rx_data[16 + i],
                )
            for i in range(2):
                self.specials += Instance(
                    "IDDR",
                    p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
                    i_C=ClockSignal("phy_pipe_half"),
                    i_CE=1,
                    i_S=0,
                    i_R=0,
                    i_D=usb_pipe_data.rx_datak[i],
                    o_Q1=phy_pipe_rx_datak[i],
                    o_Q2=phy_pipe_rx_datak[2 + i],
                )
            for i in range(3):
                self.specials += Instance(
                    "IDDR",
                    p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
                    i_C=ClockSignal("phy_pipe_half"),
                    i_CE=1,
                    i_S=0,
                    i_R=0,
                    i_D=usb_pipe_status.rx_status[i],
                    o_Q1=phy_rx_status[i],
                    o_Q2=phy_rx_status[3 + i],
                )
            self.specials += Instance(
                "IDDR",
                p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
                i_C=ClockSignal("phy_pipe_half"),
                i_CE=1,
                i_S=0,
                i_R=0,
                i_D=usb_pipe_status_phy_status,
                o_Q1=phy_phy_status[0],
                o_Q2=phy_phy_status[1],
            )

            # ddr outputs
            self.specials += Instance(
                "ODDR",
                p_DDR_CLK_EDGE="SAME_EDGE",
                i_C=ClockSignal("phy_pipe_tx_phase"),
                i_CE=1,
                i_S=0,
                i_R=0,
                i_D1=1,
                i_D2=0,
                o_Q=usb_pipe_data.tx_clk,
            )
            for i in range(16):
                self.specials += Instance(
                    "ODDR",
                    p_DDR_CLK_EDGE="SAME_EDGE",
                    i_C=ClockSignal("phy_pipe_half_phase"),
                    i_CE=1,
                    i_S=0,
                    i_R=0,
                    i_D1=phy_pipe_tx_data[i],
                    i_D2=phy_pipe_tx_data[16 + i],
                    o_Q=usb_pipe_data.tx_data[i],
                )
            for i in range(2):
                self.specials += Instance(
                    "ODDR",
                    p_DDR_CLK_EDGE="SAME_EDGE",
                    i_C=ClockSignal("phy_pipe_half_phase"),
                    i_CE=1,
                    i_S=0,
                    i_R=0,
                    i_D1=phy_pipe_tx_datak[i],
                    i_D2=phy_pipe_tx_datak[2 + i],
                    o_Q=usb_pipe_data.tx_datak[i],
                )

            # usb3 debug
            if with_usb3_analyzer:
                analyzer_signals = [
                    dbg_pipe_state, dbg_ltssm_state,
                    usb_pipe_ctrl.tx_detrx_lpbk, usb_pipe_ctrl.tx_elecidle,
                    usb_pipe_status.rx_elecidle, usb_pipe_ctrl.power_down,
                    usb_pipe_status.phy_status, usb_pipe_status.pwr_present,
                    usb_pipe_ctrl.tx_oneszeros, usb_pipe_ctrl.tx_deemph,
                    usb_pipe_ctrl.tx_margin, usb_pipe_ctrl.tx_swing,
                    usb_pipe_ctrl.rx_polarity, usb_pipe_ctrl.rx_termination,
                    usb_pipe_ctrl.rate, usb_pipe_ctrl.elas_buf_mode,
                    phy_pipe_rx_valid, phy_pipe_rx_data, phy_pipe_rx_datak,
                    phy_pipe_tx_data, phy_pipe_tx_datak
                ]
                self.submodules.analyzer = LiteScopeAnalyzer(
                    analyzer_signals, 2048, cd="phy_pipe_half")
Example #12
0
    def __init__(self, pads, wires=4, with_tristate=True):
        self.wishbone = wishbone.Interface()

        # # #
        self.__doc__ = self.__doc__.format(wires)
        if wires == 4:
            self.mod_doc = Spi4WireDocumentation()
        elif wires == 3:
            self.mod_doc = Spi3WireDocumentation()
        elif wires == 2:
            self.mod_doc = Spi2WireDocumentation()

        clk = Signal()
        cs_n = Signal()
        mosi = Signal()
        miso = Signal()
        miso_en = Signal()

        counter = Signal(8)
        write_offset = Signal(5)
        command = Signal(8)
        address = Signal(32)
        value = Signal(32)
        wr = Signal()
        sync_byte = Signal(8)

        self.specials += [
            MultiReg(pads.clk, clk),
        ]
        if wires == 2:
            io = TSTriple()
            self.specials += io.get_tristate(pads.mosi)
            self.specials += MultiReg(io.i, mosi)
            self.comb += io.o.eq(miso)
            self.comb += io.oe.eq(miso_en)
        elif wires == 3:
            self.specials += MultiReg(pads.cs_n, cs_n),
            io = TSTriple()
            self.specials += io.get_tristate(pads.mosi)
            self.specials += MultiReg(io.i, mosi)
            self.comb += io.o.eq(miso)
            self.comb += io.oe.eq(miso_en)
        elif wires == 4:
            self.specials += MultiReg(pads.cs_n, cs_n),
            self.specials += MultiReg(pads.mosi, mosi)
            if with_tristate:
                self.specials += Tristate(pads.miso, miso, ~cs_n)
            else:
                self.comb += pads.miso.eq(miso)
        else:
            raise ValueError("`wires` must be 2, 3, or 4")

        clk_last = Signal()
        clk_rising = Signal()
        clk_falling = Signal()
        self.sync += clk_last.eq(clk)
        self.comb += clk_rising.eq(clk & ~clk_last)
        self.comb += clk_falling.eq(~clk & clk_last)

        fsm = FSM(reset_state="IDLE")
        fsm = ResetInserter()(fsm)
        self.submodules += fsm
        self.comb += fsm.reset.eq(cs_n)

        # Connect the Wishbone bus up to our values
        self.comb += [
            self.wishbone.adr.eq(address[2:]),
            self.wishbone.dat_w.eq(value),
            self.wishbone.sel.eq(2**len(self.wishbone.sel) - 1)
        ]

        # Constantly have the counter increase, except when it's reset
        # in the IDLE state
        self.sync += If(cs_n, counter.eq(0)).Elif(clk_rising,
                                                  counter.eq(counter + 1))

        if wires == 2:
            fsm.act(
                "IDLE", miso_en.eq(0), NextValue(miso, 1),
                If(clk_rising, NextValue(sync_byte, Cat(mosi, sync_byte))),
                If(
                    sync_byte[0:7] == 0b101011,
                    NextState("GET_TYPE_BYTE"),
                    NextValue(counter, 0),
                    NextValue(command, mosi),
                ))
        elif wires == 3 or wires == 4:
            fsm.act(
                "IDLE",
                miso_en.eq(0),
                NextValue(miso, 1),
                If(
                    clk_rising,
                    NextState("GET_TYPE_BYTE"),
                    NextValue(command, mosi),
                ),
            )
        else:
            raise ValueError("invalid `wires` count: {}".format(wires))

        # Determine if it's a read or a write
        fsm.act(
            "GET_TYPE_BYTE",
            miso_en.eq(0),
            NextValue(miso, 1),
            If(
                counter == 8,
                # Write value
                If(
                    command == 0,
                    NextValue(wr, 1),
                    NextState("READ_ADDRESS"),

                    # Read value
                ).Elif(
                    command == 1,
                    NextValue(wr, 0),
                    NextState("READ_ADDRESS"),
                ).Else(NextState("END"), ),
            ),
            If(
                clk_rising,
                NextValue(command, Cat(mosi, command)),
            ),
        )

        fsm.act(
            "READ_ADDRESS",
            miso_en.eq(0),
            If(
                counter == 32 + 8,
                If(
                    wr,
                    NextState("READ_VALUE"),
                ).Else(NextState("READ_WISHBONE"), )),
            If(
                clk_rising,
                NextValue(address, Cat(mosi, address)),
            ),
        )

        fsm.act(
            "READ_VALUE",
            miso_en.eq(0),
            If(
                counter == 32 + 32 + 8,
                NextState("WRITE_WISHBONE"),
            ),
            If(
                clk_rising,
                NextValue(value, Cat(mosi, value)),
            ),
        )

        fsm.act(
            "WRITE_WISHBONE",
            self.wishbone.stb.eq(1),
            self.wishbone.we.eq(1),
            self.wishbone.cyc.eq(1),
            miso_en.eq(1),
            If(
                self.wishbone.ack | self.wishbone.err,
                NextState("WAIT_BYTE_BOUNDARY"),
            ),
        )

        fsm.act(
            "READ_WISHBONE",
            self.wishbone.stb.eq(1),
            self.wishbone.we.eq(0),
            self.wishbone.cyc.eq(1),
            miso_en.eq(1),
            If(
                self.wishbone.ack | self.wishbone.err,
                NextState("WAIT_BYTE_BOUNDARY"),
                NextValue(value, self.wishbone.dat_r),
            ),
        )

        fsm.act(
            "WAIT_BYTE_BOUNDARY",
            miso_en.eq(1),
            If(
                clk_falling,
                If(
                    counter[0:3] == 0,
                    NextValue(miso, 0),
                    # For writes, fill in the 0 byte response
                    If(
                        wr,
                        NextState("WRITE_WR_RESPONSE"),
                    ).Else(NextState("WRITE_RESPONSE"), ),
                ),
            ),
        )

        # Write the "01" byte that indicates a response
        fsm.act(
            "WRITE_RESPONSE",
            miso_en.eq(1),
            If(
                clk_falling,
                If(
                    counter[0:3] == 0b111,
                    NextValue(miso, 1),
                ).Elif(counter[0:3] == 0, NextValue(write_offset, 31),
                       NextState("WRITE_VALUE")),
            ),
        )

        # Write the actual value
        fsm.act(
            "WRITE_VALUE",
            miso_en.eq(1),
            NextValue(miso, value >> write_offset),
            If(
                clk_falling,
                NextValue(write_offset, write_offset - 1),
                If(
                    write_offset == 0,
                    NextValue(miso, 0),
                    NextState("END"),
                ),
            ),
        )

        fsm.act(
            "WRITE_WR_RESPONSE",
            miso_en.eq(1),
            If(
                clk_falling,
                If(
                    counter[0:3] == 0,
                    NextState("END"),
                ),
            ),
        )

        if wires == 3 or wires == 4:
            fsm.act(
                "END",
                miso_en.eq(1),
            )
        elif wires == 2:
            fsm.act("END", miso_en.eq(0), NextValue(sync_byte, 0),
                    NextState("IDLE"))
        else:
            raise ValueError("invalid `wires` count: {}".format(wires))
Example #13
0
    def __init__(self, pads, sys_clk_freq=100e6):
        memtype = "DDR3"
        tck = 2 / (2 * 2 * sys_clk_freq)
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        nphases = 2

        self._wlevel_en = CSRStorage()
        self._wlevel_strobe = CSR()

        self._dly_sel = CSRStorage(databits // 8)

        self._rdly_dq_rst = CSR()
        self._rdly_dq_inc = CSR()
        self._rdly_dq_bitslip_rst = CSR()
        self._rdly_dq_bitslip = CSR()

        self._wdly_dq_rst = CSR()
        self._wdly_dq_inc = CSR()
        self._wdly_dqs_rst = CSR()
        self._wdly_dqs_inc = CSR()

        # compute phy settings
        cl, cwl = get_cl_cw(memtype, tck)
        cl_sys_latency = get_sys_latency(nphases, cl)
        cwl_sys_latency = get_sys_latency(nphases, cwl)

        rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
        wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
        self.settings = PhySettings(
            memtype=memtype,
            dfi_databits=4 * databits,
            nranks=nranks,
            nphases=nphases,
            rdphase=rdphase,
            wrphase=wrphase,
            rdcmdphase=rdcmdphase,
            wrcmdphase=wrcmdphase,
            cl=cl,
            cwl=cwl,
            read_latency=2 + cl_sys_latency + 2 + log2_int(4 // nphases) +
            3,  # FIXME
            write_latency=cwl_sys_latency)

        self.dfi = Interface(addressbits, bankbits, nranks, 4 * databits, 4)

        # # #

        bl8_sel = Signal()

        # Clock
        for i in range(len(pads.clk_p)):
            sd_clk_se = Signal()
            self.specials += [
                Instance("ODDRX2F",
                         i_D0=0,
                         i_D1=1,
                         i_D2=0,
                         i_D3=1,
                         i_ECLK=ClockSignal("sys2x"),
                         i_SCLK=ClockSignal(),
                         i_RST=ResetSignal(),
                         o_Q=pads.clk_p[i]),
            ]

        # Addresses and commands
        for i in range(addressbits):
            self.specials += \
                Instance("ODDRX2F",
                    i_D0=self.dfi.phases[0].address[i],
                    i_D1=self.dfi.phases[0].address[i],
                    i_D2=self.dfi.phases[1].address[i],
                    i_D3=self.dfi.phases[1].address[i],
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    i_RST=ResetSignal(),
                    o_Q=pads.a[i]
                )
        for i in range(bankbits):
            self.specials += \
                 Instance("ODDRX2F",
                    i_D0=self.dfi.phases[0].bank[i],
                    i_D1=self.dfi.phases[0].bank[i],
                    i_D2=self.dfi.phases[1].bank[i],
                    i_D3=self.dfi.phases[1].bank[i],
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    i_RST=ResetSignal(),
                    o_Q=pads.ba[i]
                )
        controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
        if hasattr(pads, "reset_n"):
            controls.append("reset_n")
        if hasattr(pads, "cs_n"):
            controls.append("cs_n")
        for name in controls:
            for i in range(len(getattr(pads, name))):
                self.specials += \
                    Instance("ODDRX2F",
                        i_D0=getattr(self.dfi.phases[0], name)[i],
                        i_D1=getattr(self.dfi.phases[0], name)[i],
                        i_D2=getattr(self.dfi.phases[1], name)[i],
                        i_D3=getattr(self.dfi.phases[1], name)[i],
                        i_ECLK=ClockSignal("sys2x"),
                        i_SCLK=ClockSignal(),
                        i_RST=ResetSignal(),
                        o_Q=getattr(pads, name)[i]
                )

        # DQSBUFM
        dqsr90 = Signal()
        dqsw270 = Signal()
        dqsw = Signal()
        rdpntr = Signal(3)
        wrpntr = Signal(3)
        self.specials += Instance(
            "DQSBUFM",
            i_DDRDEL=0b0,
            i_PAUSE=0b0,
            i_DQSI=pads.dqs_p[0],
            i_READ0=0b0,
            i_READ1=0b0,
            i_READCLKSEL0=0b0,
            i_READCLKSEL1=0b0,
            i_READCLKSEL2=0b0,
            i_DYNDELAY0=0b0,
            i_DYNDELAY1=0b0,
            i_DYNDELAY2=0b0,
            i_DYNDELAY3=0b0,
            i_DYNDELAY4=0b0,
            i_DYNDELAY5=0b0,
            i_DYNDELAY6=0b0,
            i_DYNDELAY7=0b0,
            i_RDLOADN=0,
            i_RDMOVE=0,
            i_RDDIRECTION=0,
            i_WRLOADN=0,
            i_WRMOVE=0,
            i_WRDIRECTION=0,

            #o_RDCFLAG=,
            #o_WRCFLAG=,

            #o_DATAVALID=,
            #o_BURSTDET=,
            o_DQSR90=dqsr90,
            o_RDPNTR0=rdpntr[0],
            o_RDPNTR1=rdpntr[1],
            o_RDPNTR2=rdpntr[2],
            o_WRPNTR0=wrpntr[0],
            o_WRPNTR1=wrpntr[1],
            o_WRPNTR2=wrpntr[2],
            i_SCLK=ClockSignal("sys"),
            i_ECLK=ClockSignal("sys2x"),
            o_DQSW270=dqsw270,
            o_DQSW=dqsw)

        # DQS and DM
        oe_dqs = Signal()
        dqs_preamble = Signal()
        dqs_postamble = Signal()
        dqs_serdes_pattern = Signal(8, reset=0b01010101)
        self.comb += \
            If(self._wlevel_en.storage,
                If(self._wlevel_strobe.re,
                    dqs_serdes_pattern.eq(0b00000001)
                ).Else(
                    dqs_serdes_pattern.eq(0b00000000)
                )
            ).Elif(dqs_preamble | dqs_postamble,
                dqs_serdes_pattern.eq(0b0000000)
            ).Else(
                dqs_serdes_pattern.eq(0b01010101)
            )

        for i in range(databits // 8):
            dm_o_nodelay = Signal()
            dm_data = Signal(8)
            dm_data_d = Signal(8)
            dm_data_muxed = Signal(4)
            self.comb += dm_data.eq(
                Cat(self.dfi.phases[0].wrdata_mask[0 * databits // 8 + i],
                    self.dfi.phases[0].wrdata_mask[1 * databits // 8 + i],
                    self.dfi.phases[0].wrdata_mask[2 * databits // 8 + i],
                    self.dfi.phases[0].wrdata_mask[3 * databits // 8 + i],
                    self.dfi.phases[1].wrdata_mask[0 * databits // 8 + i],
                    self.dfi.phases[1].wrdata_mask[1 * databits // 8 + i],
                    self.dfi.phases[1].wrdata_mask[2 * databits // 8 + i],
                    self.dfi.phases[1].wrdata_mask[3 * databits // 8 + i]), )
            self.sync += dm_data_d.eq(dm_data)
            self.comb += \
                If(bl8_sel,
                    dm_data_muxed.eq(dm_data_d[4:])
                ).Else(
                    dm_data_muxed.eq(dm_data[:4])
                )
            self.specials += \
                Instance("ODDRX2DQA",
                    i_D0=dm_data_muxed[0],
                    i_D1=dm_data_muxed[1],
                    i_D2=dm_data_muxed[2],
                    i_D3=dm_data_muxed[3],
                    i_RST=ResetSignal(),
                    i_DQSW270=dqsw270,
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    o_Q=dm_o_nodelay
                )
            self.specials += \
                Instance("DELAYF",
                i_A=dm_o_nodelay,
                i_LOADN=self._dly_sel.storage[i] & self._wdly_dq_rst.re,
                i_MOVE=self._dly_sel.storage[i] & self._wdly_dq_inc.re,
                i_DIRECTION=0,
                o_Z=pads.dm[i],
                #o_CFLAG=,
            )

            dqs_nodelay = Signal()
            dqs_delayed = Signal()
            dqs_oe = Signal()
            self.specials += \
                Instance("ODDRX2DQSB",
                    i_D0=dqs_serdes_pattern[0],
                    i_D1=dqs_serdes_pattern[1],
                    i_D2=dqs_serdes_pattern[2],
                    i_D3=dqs_serdes_pattern[3],
                    i_RST=ResetSignal(),
                    i_DQSW=dqsw,
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    o_Q=dqs_nodelay
                )
            self.specials += \
                Instance("DELAYF",
                i_A=dqs_nodelay,
                i_LOADN=self._dly_sel.storage[i] & self._wdly_dqs_rst.re,
                i_MOVE=self._dly_sel.storage[i] & self._wdly_dqs_inc.re,
                i_DIRECTION=0,
                o_Z=dqs_delayed,
                #o_CFLAG=,
            )
            self.specials += \
                Instance("TSHX2DQSA",
                    i_T0=oe_dqs,
                    i_T1=oe_dqs,
                    i_SCLK=ClockSignal(),
                    i_ECLK=ClockSignal("sys2x"),
                    i_DQSW=dqsw,
                    i_RST=ResetSignal(),
                    o_Q=dqs_oe,
                )
            self.specials += Tristate(pads.dqs_p[i], dqs_delayed, dqs_oe)

        # DQ
        oe_dq = Signal()
        for i in range(databits):
            dq_o_nodelay = Signal()
            dq_o_delayed = Signal()
            dq_i_nodelay = Signal()
            dq_i_delayed = Signal()
            dq_oe = Signal()
            dq_data = Signal(8)
            dq_data_d = Signal(8)
            dq_data_muxed = Signal(4)
            self.comb += dq_data.eq(
                Cat(self.dfi.phases[0].wrdata[0 * databits + i],
                    self.dfi.phases[0].wrdata[1 * databits + i],
                    self.dfi.phases[0].wrdata[2 * databits + i],
                    self.dfi.phases[0].wrdata[3 * databits + i],
                    self.dfi.phases[1].wrdata[0 * databits + i],
                    self.dfi.phases[1].wrdata[1 * databits + i],
                    self.dfi.phases[1].wrdata[2 * databits + i],
                    self.dfi.phases[1].wrdata[3 * databits + i]))
            self.sync += dq_data_d.eq(dq_data)
            self.comb += \
                If(bl8_sel,
                    dq_data_muxed.eq(dq_data_d[4:])
                ).Else(
                    dq_data_muxed.eq(dq_data[:4])
                )
            self.specials += \
                Instance("ODDRX2DQA",
                    i_D0=dq_data_muxed[0],
                    i_D1=dq_data_muxed[1],
                    i_D2=dq_data_muxed[2],
                    i_D3=dq_data_muxed[3],
                    i_RST=ResetSignal(),
                    i_DQSW270=dqsw270,
                    i_ECLK=ClockSignal("sys2x"),
                    i_SCLK=ClockSignal(),
                    o_Q=dq_o_nodelay
                )

            self.specials += \
                Instance("DELAYF",
                    i_A=dq_o_nodelay,
                    i_LOADN=self._dly_sel.storage[i//8] & self._wdly_dq_rst.re,
                    i_MOVE=self._dly_sel.storage[i//8] & self._wdly_dq_inc.re,
                    i_DIRECTION=0,
                    o_Z=dq_o_delayed,
                    #o_CFLAG=,
                )
            dq_i_data = Signal(8)
            dq_i_data_d = Signal(8)
            self.specials += \
                Instance("IDDRX2DQA",
                    i_D=dq_i_delayed,
                    i_RST=ResetSignal(),
                    i_DQSR90=dqsr90,
                    i_SCLK=ClockSignal(),
                    i_ECLK=ClockSignal("sys2x"),
                    i_RDPNTR0=rdpntr[0],
                    i_RDPNTR1=rdpntr[1],
                    i_RDPNTR2=rdpntr[2],
                    i_WRPNTR0=wrpntr[0],
                    i_WRPNTR1=wrpntr[1],
                    i_WRPNTR2=wrpntr[2],
                    o_Q0=dq_i_data[0],
                    o_Q1=dq_i_data[1],
                    o_Q2=dq_i_data[2],
                    o_Q3=dq_i_data[3],
                )
            dq_bitslip = BitSlip(4)
            self.comb += dq_bitslip.i.eq(dq_i_data)
            self.sync += \
                If(self._dly_sel.storage[i//8],
                    If(self._rdly_dq_bitslip_rst.re,
                        dq_bitslip.value.eq(0)
                    ).Elif(self._rdly_dq_bitslip.re,
                        dq_bitslip.value.eq(dq_bitslip.value + 1)
                    )
                )
            self.submodules += dq_bitslip
            self.sync += dq_i_data_d.eq(dq_i_data)
            self.comb += [
                self.dfi.phases[0].rddata[i].eq(dq_bitslip.o[0]),
                self.dfi.phases[0].rddata[databits + i].eq(dq_bitslip.o[1]),
                self.dfi.phases[1].rddata[i].eq(dq_bitslip.o[2]),
                self.dfi.phases[1].rddata[databits + i].eq(dq_bitslip.o[3])
            ]
            #self.specials += \
            #    Instance("DELAYF",
            #        i_A=dq_i_nodelay,
            #        i_LOADN=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re,
            #        i_MOVE=self._dly_sel.storage[i//8] & self._wdly_dq_inc.re,
            #        i_DIRECTION=0,
            #        o_Z=dq_i_delayed,
            #        #o_CFLAG=,
            #    )
            self.specials += \
                Instance("TSHX2DQA",
                    i_T0=oe_dq,
                    i_T1=oe_dq,
                    i_SCLK=ClockSignal(),
                    i_ECLK=ClockSignal("sys2x"),
                    i_DQSW270=dqsw270,
                    i_RST=ResetSignal(),
                    o_Q=dq_oe,
                )
            self.specials += Tristate(pads.dq[i], dq_o_delayed, dq_oe,
                                      dq_i_delayed)

        # Flow control
        #
        # total read latency:
        #  N cycles through ODDRX2DQA FIXME
        #  cl_sys_latency cycles CAS
        #  M cycles through IDDRX2DQA FIXME
        rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en
        for i in range(self.settings.read_latency - 1):
            n_rddata_en = Signal()
            self.sync += n_rddata_en.eq(rddata_en)
            rddata_en = n_rddata_en
        self.sync += [
            phase.rddata_valid.eq(rddata_en | self._wlevel_en.storage)
            for phase in self.dfi.phases
        ]

        oe = Signal()
        last_wrdata_en = Signal(cwl_sys_latency + 3)
        wrphase = self.dfi.phases[self.settings.wrphase]
        self.sync += last_wrdata_en.eq(
            Cat(wrphase.wrdata_en, last_wrdata_en[:-1]))
        self.comb += oe.eq(last_wrdata_en[cwl_sys_latency - 1]
                           | last_wrdata_en[cwl_sys_latency]
                           | last_wrdata_en[cwl_sys_latency + 1]
                           | last_wrdata_en[cwl_sys_latency + 2])
        self.sync += \
            If(self._wlevel_en.storage,
                oe_dqs.eq(1), oe_dq.eq(0)
            ).Else(
                oe_dqs.eq(oe), oe_dq.eq(oe)
            )

        self.sync += bl8_sel.eq(last_wrdata_en[cwl_sys_latency - 1])
Example #14
0
File: core.py Project: tcal-x/litex
    def __init__(self, pads=None):
        if pads is None:
            pads = Record(self.jtag_layout)
        self.pads = pads
        self.dmbus = wishbone.Interface()
        self.sbbus = wishbone.Interface()
        dmbus = Record(obi_layout)
        sbbus = Record(obi_layout)

        self.submodules.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus)
        self.submodules.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus)

        self.debug_req = Signal()
        self.ndmreset = Signal()

        tdo_i = Signal()
        tdo_o = Signal()
        tdo_oe = Signal()

        self.specials += Tristate(pads.tdo, tdo_o, tdo_oe, tdo_i)

        self.dm_params = dict(
            # Clk / Rst.
            i_clk=ClockSignal("sys"),
            i_rst_n=~ResetSignal("sys"),
            o_ndmreset=self.ndmreset,
            o_debug_req=self.debug_req,

            # Slave Bus.
            i_dm_req=dmbus.req,
            i_dm_we=dmbus.we,
            i_dm_addr=dmbus.addr,
            i_dm_be=dmbus.be,
            i_dm_wdata=dmbus.wdata,
            o_dm_rdata=dmbus.rdata,

            # Master Bus.
            o_sb_req=sbbus.req,
            o_sb_addr=sbbus.addr,
            o_sb_we=sbbus.we,
            o_sb_wdata=sbbus.wdata,
            o_sb_be=sbbus.be,
            i_sb_gnt=sbbus.gnt,
            i_sb_rvalid=sbbus.rvalid,
            i_sb_rdata=sbbus.rdata,

            # JTAG.
            i_tck=pads.tck,
            i_tms=pads.tms,
            i_trst_n=pads.trst,
            i_tdi=pads.tdi,
            o_tdo=tdo_o,
            o_tdo_oe=tdo_oe,
        )

        self.comb += [
            dmbus.gnt.eq(dmbus.req),
            dmbus.rvalid.eq(dmbus.gnt),
        ]

        self.specials += Instance("dm_wrap", **self.dm_params)
Example #15
0
    def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"):
        """
        Simple SPI flash.
        Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
        Read). Only supports mode3 (cpol=1, cpha=1).
        """
        SpiFlashCommon.__init__(self, pads)
        self.bus = bus = wishbone.Interface()
        spi_width = len(pads.dq)
        max_transfer_size = 8*8
        assert spi_width >= 2

        if with_bitbang:
            self.bitbang = CSRStorage(4, reset_less=True, fields=[
                CSRField("mosi", description="Output value for MOSI pin, valid whenever ``dir`` is ``0``."),
                CSRField("clk", description="Output value for SPI CLK pin."),
                CSRField("cs_n", description="Output value for SPI CSn pin."),
                CSRField("dir", description="Sets the direction for *ALL* SPI data pins except CLK and CSn.", values=[
                    ("0", "OUT", "SPI pins are all output"),
                    ("1", "IN", "SPI pins are all input"),
                ])
            ], description="""
                Bitbang controls for SPI output.  Only standard 1x SPI is supported, and as
                a result all four wires are ganged together.  This means that it is only possible
                to perform half-duplex operations, using this SPI core.
            """)
            self.miso = CSRStatus(description="Incoming value of MISO signal.")
            self.bitbang_en = CSRStorage(description="Write a ``1`` here to disable memory-mapped mode and enable bitbang mode.")

        queue = self.queue = CSRStatus(4)
        in_len = self.in_len = CSRStorage(4)
        out_len = self.out_len = CSRStorage(4)
        in_left = self.in_left = Signal(max=2**8)
        out_left = self.out_left = Signal(max=2**8)
        self.quad_transfer = Signal(reset=0)
        spi_in = self.spi_in = CSRStorage(max_transfer_size)
        spi_out = self.spi_out = CSRStatus(max_transfer_size)

        cs_n = Signal(reset=1)
        clk = Signal()
        dq_oe = Signal()
        wbone_width = len(bus.dat_r)

        cmd_width = 8
        addr_width = 24

        dq = TSTriple(spi_width)

        sr = Signal(max(cmd_width, addr_width, wbone_width))
        if endianness == "big":
            self.comb += bus.dat_r.eq(sr)
        else:
            self.comb += bus.dat_r.eq(reverse_bytes(sr))

        self.specials.dq0 = Tristate(pads.dq[0], o=dq.o[0], i=dq.i[0], oe=dq.oe)
        self.specials.dq1 = Tristate(pads.dq[1], o=dq.o[1], i=dq.i[1], oe=dq.oe)
        if with_bitbang:
            # Keep DQ2,DQ3 as outputs during bitbang, this ensures they activate ~WP or ~HOLD functions
            self.specials.dq2 = Tristate(pads.dq[2], o=dq.o[2], i=dq.i[2], oe=(dq.oe | self.bitbang_en.storage))
            self.specials.dq3 = Tristate(pads.dq[3], o=dq.o[3], i=dq.i[3], oe=(dq.oe | self.bitbang_en.storage))
        else:
            self.specials.dq2 = Tristate(pads.dq[2], o=dq.o[2], i=dq.i[2], oe=dq.oe)
            self.specials.dq3 = Tristate(pads.dq[3], o=dq.o[3], i=dq.i[3], oe=dq.oe)

        sr = Signal(max(cmd_width, addr_width, wbone_width, max_transfer_size))

        if endianness == "big":
            self.comb += bus.dat_r.eq(sr[:wbone_width])
        else:
            self.comb += bus.dat_r.eq(reverse_bytes(sr[:wbone_width]))
        hw_read_logic_single = [
            pads.clk.eq(clk),
            pads.cs_n.eq(cs_n),
            dq.o.eq(sr[-spi_width:]),
            dq.oe.eq(dq_oe)
        ]
        hw_read_logic_quad = [
            pads.clk.eq(clk),
            pads.cs_n.eq(cs_n),
            dq.o.eq(Cat(sr[-1:], Replicate(1, 3))),
            dq.oe.eq(dq_oe)
        ]

        if with_bitbang:
            bitbang_logic = [
                pads.clk.eq(self.bitbang.storage[1]),
                pads.cs_n.eq(self.bitbang.storage[2]),

                # In Dual/Quad mode, no single data pin is consistently
                # an input or output thanks to dual/quad reads, so we need a bit
                # to swap direction of the pins. Aside from this additional bit,
                # bitbang mode is identical for Single/Dual/Quad; dq[0] is mosi
                # and dq[1] is miso, meaning remaining data pin values don't
                # appear in CSR registers.
                If(self.bitbang.storage[3],
                    dq.oe.eq(0)
                ).Else(
                    dq.oe.eq(1)
                ),
                If(self.bitbang.storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
                    self.miso.status.eq(dq.i[1])
                ),
                dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))
            ]

            self.comb += [
                If(self.bitbang_en.storage,
                    bitbang_logic
                ).Elif(self.quad_transfer,
                    hw_read_logic_single
                ).Else(
                    hw_read_logic_quad
                )
            ]

        else:
            self.comb += [
                If(self.quad_transfer,
                    hw_read_logic_single
                ).Else(
                    hw_read_logic_quad
                )
            ]

        if div < 2:
            raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))

        # spi is byte-addressed, prefix by zeros
        z = Replicate(0, log2_int(wbone_width//8))
        i = Signal(max=div)
        dqi = Signal(spi_width)

        # SPI or memmap mode
        self.mode = Signal()

        self.sync += [
            If(i == div//2 - 1,
                clk.eq(1),
                dqi.eq(dq.i),
            ),
            If(i == div - 1,
                i.eq(0),
                clk.eq(0),
               If(self.quad_transfer,
                  sr.eq(Cat(dqi, sr[:-spi_width]))
               ).Else(
                   sr.eq(Cat(dqi[1], sr[:-1]))
                  )
            ).Else(
                i.eq(i + 1),
            ),
        ]

        read_seq = [
            (4*cmd_width//spi_width*div,
                [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(_QIOFR), self.quad_transfer.eq(0)]),
            (addr_width//spi_width*div,
                [sr[-addr_width:].eq(Cat(z, bus.adr)), self.quad_transfer.eq(1)]),
            ((1+dummy + wbone_width//spi_width)*div,
                [dq_oe.eq(0)]),
            (1,
                [bus.ack.eq(1), cs_n.eq(1)]),
            (div, # tSHSL!
                [bus.ack.eq(0)]),
            (0,
             [queue.status[0].eq(0)]),
        ]


        write_seq = [
            (4*cmd_width//spi_width*div,
                [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(_QIOPP), self.quad_transfer.eq(0)]),
            (addr_width//spi_width*div,
                [sr[-addr_width:].eq(Cat(z, bus.adr)), self.quad_transfer.eq(1)]),
            ((wbone_width//spi_width)*div,
                [sr[-wbone_width:].eq(reverse_bytes(bus.dat_w))]),
            (1,
                [bus.ack.eq(1), cs_n.eq(1)]),
            (div,
                [bus.ack.eq(0)]),
            (0,
             [queue.status[1].eq(0)]),
        ]

        # prepare spi transfer
        self.sync += If(self.out_len.re & (self.out_len.storage != 0) & self.en_quad.storage[0],
                        self.out_left.eq(Cat(1, self.out_len.storage)
                        )
        )

        self.sync += If(self.out_len.re & (self.out_len.storage == 0),
                        self.out_left.eq(0)
        )
        self.sync += If(self.out_len.re & (self.out_len.storage != 0) & ~self.en_quad.storage[0],
                        self.out_left.eq(Cat(1, Replicate(0, 2), self.out_len.storage))
        )
        self.sync += If(self.in_len.re & (self.in_len.storage != 0) & ~self.en_quad.storage[0],
                        [queue.status[2].eq(1),
                         self.in_left.eq(Cat(Replicate(0, 3), in_len.storage)),
                         self.quad_transfer.eq(0)]
        )

        # write data to sr
        self.sync += If(queue.status[2] & (i == div - 1) & ~self.en_quad.storage[0],
                        sr[-max_transfer_size:].eq(self.spi_in.storage), queue.status[2].eq(0), queue.status[3].eq(1), cs_n.eq(0), dq_oe.eq(1))

        # count spi to slave transfer cycles
        self.sync += If(queue.status[3] & (self.in_left > 0) & (i == div - 1), self.in_left.eq(self.in_left - 1), dq_oe.eq(1))
        # count spi to master transfer cycles
        self.sync += If(queue.status[3] & (self.in_left < 1) & (self.out_left > 0) & (i == div - 1), self.out_left.eq(self.out_left - 1), dq_oe.eq(0))

        #end transmision and read data from sr
        self.sync += If(~self.in_len.re & (in_left < 1) & (out_left < 1) & queue.status[3], queue.status[3].eq(0), cs_n.eq(1),
                        If(self.out_len.storage == 1, self.spi_out.status.eq(Cat(Replicate(0, 8*7), sr))
                        ).Elif(self.out_len.storage == 2, self.spi_out.status.eq(Cat(Replicate(0, 8*6), sr))
                        ).Elif(self.out_len.storage == 3, self.spi_out.status.eq(Cat(Replicate(0, 8*5), sr))
                        ).Elif(self.out_len.storage == 4, self.spi_out.status.eq(Cat(Replicate(0, 8*4), sr))
                        ).Elif(self.out_len.storage == 5, self.spi_out.status.eq(Cat(Replicate(0, 8*3), sr))
                        ).Elif(self.out_len.storage == 6, self.spi_out.status.eq(Cat(Replicate(0, 8*2), sr))
                        ).Elif(self.out_len.storage == 7, self.spi_out.status.eq(Cat(Replicate(0, 8*1), sr))
                        ).Else(self.spi_out.status.eq(sr)))

        # detect mem map access
        self.sync += If(~self.mode & bus.cyc & bus.stb & ~bus.we, queue.status[0].eq(1))
        self.sync += If(~self.mode & bus.cyc & bus.stb & bus.we, queue.status[1].eq(1))

        self.sync += timeline(queue.status[0] & ~self.en_quad.storage[0] & (i == div - 1), accumulate_timeline_deltas(read_seq))
        self.sync += timeline(queue.status[1] & ~self.en_quad.storage[0] & (i == div - 1), accumulate_timeline_deltas(write_seq))
Example #16
0
def test_tristate(triple, expected):
    assert Tristate.emit_vhdl(
        triple.get_tristate(foo), NameSpace(), None) == expected
Example #17
0
    def __init__(self, pads, cl=2):
        addressbits = len(pads.a)
        bankbits = len(pads.ba)
        nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
        databits = len(pads.dq)
        assert databits % 8 == 0

        self.settings = PhySettings(memtype="SDR",
                                    databits=databits,
                                    dfi_databits=databits,
                                    nranks=nranks,
                                    nphases=1,
                                    rdphase=0,
                                    wrphase=0,
                                    rdcmdphase=0,
                                    wrcmdphase=0,
                                    cl=cl,
                                    read_latency=cl + 2,
                                    write_latency=0)

        self.dfi = dfi = Interface(addressbits, bankbits, nranks, databits)

        # # #

        # Command/address
        self.sync += [
            pads.a.eq(dfi.p0.address),
            pads.ba.eq(dfi.p0.bank),
            pads.cas_n.eq(dfi.p0.cas_n),
            pads.ras_n.eq(dfi.p0.ras_n),
            pads.we_n.eq(dfi.p0.we_n)
        ]
        if hasattr(pads, "cke"):
            self.sync += pads.cke.eq(dfi.p0.cke)
        if hasattr(pads, "cs_n"):
            self.sync += pads.cs_n.eq(dfi.p0.cs_n)

        # DQ/DQS/DM data
        dq_o = Signal(databits)
        dq_oe = Signal()
        dq_i = Signal(databits)
        self.sync += dq_o.eq(dfi.p0.wrdata)
        self.specials += Tristate(pads.dq, dq_o, dq_oe, dq_i)
        if hasattr(pads, "dm"):
            assert len(pads.dm) * 8 == databits
            self.sync += \
                If(dfi.p0.wrdata_en,
                    pads.dm.eq(dfi.p0.wrdata_mask)
                ).Else(
                    pads.dm.eq(0)
                )
        dq_in = Signal(databits)
        self.sync.sys_ps += dq_in.eq(dq_i)
        self.sync += dfi.p0.rddata.eq(dq_in)

        # DQ/DM control
        wrdata_en = Signal()
        self.sync += wrdata_en.eq(dfi.p0.wrdata_en)
        self.comb += dq_oe.eq(wrdata_en)

        rddata_en = Signal(cl + 2)
        self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en[:cl + 1]))
        self.comb += dfi.p0.rddata_valid.eq(rddata_en[cl + 1])