Example #1
0
    def __init__(self, clocker, sdpads, pads):
        # Rst
        if hasattr(pads, "rst"):
            self.comb += pads.rst.eq(0)

        # Clk
        self.specials += SDROutput(
            clk = ClockSignal(),
            i   = ~clocker.clk & sdpads.clk,
            o   = pads.clk
        )

        # Cmd
        self.specials += SDRTristate(
            clk = ClockSignal(),
            io  = pads.cmd,
            o   = sdpads.cmd.o,
            oe  = sdpads.cmd.oe,
            i   = sdpads.cmd.i,
        )

        # Data
        for i in range(4):
            self.specials += SDRTristate(
                clk = ClockSignal(),
                io  = pads.data[i],
                o   = sdpads.data.o[i],
                oe  = sdpads.data.oe,
                i   = sdpads.data.i[i],
            )

        # Direction (optional)
        if hasattr(pads, "cmd_dir"):
            self.specials += [
                SDROutput(
                    clk = ClockSignal(),
                    i   = sdpads.cmd.oe,
                    o   = pads.cmd_dir,
                ),
                SDROutput(
                    clk = ClockSignal(),
                    i   = sdpads.data.oe,
                    o   = pads.dat0_dir,
                ),
                SDROutput(
                    clk = ClockSignal(),
                    i   = sdpads.data.oe,
                    o   = pads.dat13_dir,
                )
            ]
Example #2
0
    def __init__(self, pads, sys_clk_freq=100e6, cl=None):
        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

        # Parameters -------------------------------------------------------------------------------
        cl = get_default_cl(memtype="SDR", tck=1 /
                            sys_clk_freq) if cl is None else cl

        # PHY settings -----------------------------------------------------------------------------
        self.settings = PhySettings(phytype="GENSDRPHY",
                                    memtype="SDR",
                                    databits=databits,
                                    dfi_databits=databits,
                                    nranks=nranks,
                                    nphases=1,
                                    rdphase=0,
                                    wrphase=0,
                                    cl=cl,
                                    read_latency=cl + 1,
                                    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)

            # Commands -----------------------------------------------------------------------------
            commands = {
                # Pad name: (DFI name,   Pad type (required or 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"),
            }
            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)):
                    self.specials += SDROutput(i=getattr(dfi.p0, dfi_name)[i],
                                               o=pad[i])

        # DQ/DM Data Path --------------------------------------------------------------------------
        for i in range(len(pads.dq)):
            self.specials += SDRTristate(
                io=pads.dq[i],
                o=dfi.p0.wrdata[i],
                oe=dfi.p0.wrdata_en,
                i=dfi.p0.rddata[i],
            )
        if hasattr(pads, "dm"):
            for i in range(len(pads.dm)):
                self.specials += SDROutput(i=dfi.p0.wrdata_en
                                           & dfi.p0.wrdata_mask[i],
                                           o=pads.dm[i])

        # DQ/DM Control Path -----------------------------------------------------------------------
        rddata_en = Signal(self.settings.read_latency)
        self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en))
        self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1])
Example #3
0
    def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay):
        self.source              = source = stream.Endpoint(spi_phy2core_layout)
        self.sink                = sink   = stream.Endpoint(spi_core2phy_layout)
        self.cs                  = Signal()
        self._spi_clk_divisor    = spi_clk_divisor = Signal(8)
        self._spi_dummy_bits     = spi_dummy_bits  = Signal(8)
        if flash.cmd_width == 1:
            self._default_dummy_bits = flash.dummy_bits if flash.fast_mode else 0
        elif flash.cmd_width == 4:
            self._default_dummy_bits = flash.dummy_bits * 3 if flash.fast_mode else 0
        else:
            raise NotImplementedError(f'Command width of {flash.cmd_width} bits is currently not supported!')
        self._default_divisor    = default_divisor

        self.clk_divisor         = clk_divisor     = CSRStorage(8, reset=self._default_divisor)
        self.dummy_bits          = dummy_bits      = CSRStorage(8, reset=self._default_dummy_bits)

        # # #

        if clock_domain != "sys":
            self.specials += MultiReg(clk_divisor.storage, spi_clk_divisor, "litespi")
            self.specials += MultiReg(dummy_bits.storage,  spi_dummy_bits,  "litespi")
        else:
            self.comb += spi_clk_divisor.eq(clk_divisor.storage)
            self.comb += spi_dummy_bits.eq(dummy_bits.storage)
        if hasattr(pads, "miso"):
            bus_width = 1
            pads.dq   = [pads.mosi, pads.miso]
        else:
            bus_width = len(pads.dq)

        assert bus_width in [1, 2, 4, 8]

        # Check if number of pads matches configured mode.
        assert flash.check_bus_width(bus_width)

        addr_bits  = flash.addr_bits
        cmd_width  = flash.cmd_width
        addr_width = flash.addr_width
        data_width = flash.bus_width
        command    = flash.read_opcode.code
        ddr        = flash.ddr

        # For Output modes there is a constant 8 dummy cycles, for I/O and DTR modes there are
        # different number of dummy cycles and in some cases they can be configurable.
        # We control a number of dummy cycles by substracting addr_width value from spi_dummy_bits,
        # so to achieve a proper number of dummy cycles when using shift_out function we need to
        # calculate total dummy bits which depends on addr_width value.
        # NOTE: these values are just default ones, in case chip has different default dummy cycles
        # for these modes or dummy cycles can be configured, please adjust the dummy bits value via
        # CSR in liblitespi accordingly.
        if (addr_width > 1):
            # DTR mode.
            if (ddr):
                if (addr_width == 2):
                    self.default_dummy_bits = 6 * addr_width
                elif (addr_width == 4):
                    self.default_dummy_bits = 8 * addr_width
                else:
                    self.default_dummy_bits = 16 * addr_width
            # I/O mode.
            else:
                if (addr_width == 2):
                    self.default_dummy_bits = 4 * addr_width
                elif (addr_width == 4):
                    self.default_dummy_bits = 6 * addr_width
                else:
                    self.default_dummy_bits = 16 * addr_width

        # Clock Generator.
        self.submodules.clkgen = clkgen = LiteSPIClkGen(pads, device, with_ddr=ddr)
        self.comb += [
            clkgen.div.eq(spi_clk_divisor),
            clkgen.sample_cnt.eq(1),
            clkgen.update_cnt.eq(1),
        ]

        # CS control.
        cs_timer = WaitTimer(cs_delay + 1) # Ensure cs_delay cycles between XFers.
        cs_out   = Signal()
        self.submodules += cs_timer
        self.comb += cs_timer.wait.eq(self.cs)
        self.comb += cs_out.eq(cs_timer.done)
        self.comb += pads.cs_n.eq(~cs_out)

        # I/Os.
        data_bits = 32
        cmd_bits  = 8

        dq_o  = Signal(len(pads.dq))
        dq_i  = Signal(len(pads.dq))
        dq_oe = Signal(len(pads.dq))

        for i in range(len(pads.dq)):
            self.specials += SDRTristate(
                io = pads.dq[i],
                o  = dq_o[i],
                oe = dq_oe[i],
                i  = dq_i[i],
            )

        # FSM.
        shift_cnt = Signal(8, reset_less=True)
        addr      = Signal(addr_bits if not ddr else addr_bits + addr_width, reset_less=True)
        data      = Signal(data_bits, reset_less=True)
        cmd       = Signal(cmd_bits,  reset_less=True)

        usr_dout  = Signal(len(sink.data),  reset_less=True)
        usr_din   = Signal(len(sink.data),  reset_less=True)
        usr_len   = Signal(len(sink.len),   reset_less=True)
        usr_width = Signal(len(sink.width), reset_less=True)
        usr_mask  = Signal(len(sink.mask),  reset_less=True)

        din_width_cases = {1: [NextValue(usr_din, Cat(dq_i[1], usr_din))]}
        for i in [2, 4, 8]:
            din_width_cases[i] = [NextValue(usr_din, Cat(dq_i[0:i], usr_din))]

        dout_width_cases = {}
        for i in [1, 2, 4, 8]:
            dout_width_cases[i] = [dq_o.eq(usr_dout[-i:])]

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act("IDLE",
            sink.ready.eq(cs_out),
            If(sink.valid & sink.ready,
                Case(sink.cmd, {
                    CMD: [
                        NextValue(addr, sink.data),
                        NextValue(cmd,  command),
                        NextState("CMD")
                    ],
                    READ: [
                        NextState("DATA")
                    ],
                    USER: [
                        NextValue(usr_dout,  sink.data << (32-sink.len)),
                        NextValue(usr_din,   0),
                        NextValue(usr_len,   sink.len),
                        NextValue(usr_width, sink.width),
                        NextValue(usr_mask,  sink.mask),
                        NextState("USER")
                    ]
                })
            )
        )

        def shift_out(width, bits, next_state, trigger=[], op=[], ddr=False):
            if type(trigger) is not list:
                trigger = [trigger]
                op      = [op]

            edge = self.clkgen.negedge if not ddr else trigger[0]
            res  = [
                self.clkgen.en.eq(1),
                If(edge,
                    NextValue(shift_cnt, shift_cnt+width),
                    If(shift_cnt == (bits-width),
                        NextValue(shift_cnt, 0),
                        NextState(next_state),
                    ),
                ),
            ]

            if len(trigger) == len(op):
                for i in range(len(trigger)):
                    res += [If(trigger[i], *op[i])]

            return res

        fsm.act("CMD",
            dq_oe.eq(cmd_oe_mask[cmd_width]),
            dq_o.eq(cmd[-cmd_width:]),
            shift_out(
                width      = cmd_width,
                bits       = cmd_bits,
                next_state = "ADDR",
                op         = [NextValue(cmd, cmd<<cmd_width)],
                trigger    = clkgen.negedge,
                ddr        = False,
            ),
        )
        fsm.act("ADDR",
            dq_oe.eq(addr_oe_mask[addr_width]),
            dq_o.eq(addr[-addr_width:]),
            If(spi_dummy_bits != 0,
                shift_out(
                    width      = addr_width,
                    bits       = len(addr),
                    next_state = "DUMMY",
                    op         = [NextValue(addr, addr<<addr_width)],
                    trigger    = clkgen.negedge if not ddr else clkgen.update,
                    ddr        = ddr
                )
            ).Else(
                shift_out(
                    width      = addr_width,
                    bits       = len(addr),
                    next_state = "IDLE",
                    op         = [NextValue(addr, addr<<addr_width)],
                    trigger    = clkgen.negedge if not ddr else clkgen.update,
                    ddr        = ddr
                )
            )
        )
        fsm.act("DUMMY",
            If(shift_cnt < 8, dq_oe.eq(addr_oe_mask[addr_width])), # output 0's for the first dummy byte
            shift_out(
                width      = addr_width,
                bits       = spi_dummy_bits,
                next_state = "IDLE"
            ),
        )
        fsm.act("DATA",
            shift_out(
                width      = data_width,
                bits       = data_bits,
                next_state = "DATA_END",
                op         = [NextValue(data, Cat(dq_i[1] if data_width == 1 else dq_i[0:data_width], data))],
                trigger    = clkgen.posedge_reg2 if not ddr else clkgen.sample,
                ddr        = ddr
            )
        )
        fsm.act("DATA_END",
            If(spi_clk_divisor > 0,
                # Last data cycle was already captured in the DATA state.
                NextState("SEND_DATA"),
            ).Elif(clkgen.posedge_reg2,
                # Capture last data cycle.
                NextValue(data, Cat(dq_i[1] if data_width == 1 else dq_i[0:data_width], data)),
                NextState("SEND_DATA"),
            )
        )
        fsm.act("USER",
            dq_oe.eq(usr_mask),
            Case(usr_width, dout_width_cases),
            shift_out(
                width      = usr_width,
                bits       = usr_len,
                next_state = "USER_END",
                trigger    = [
                    clkgen.posedge_reg2, # data sampling
                    clkgen.negedge,      # data update
                ],
                op = [
                    [Case(usr_width, din_width_cases)],
                    [NextValue(usr_dout, usr_dout<<usr_width)],
                ],
                ddr = False)
        )
        fsm.act("USER_END",
            If(spi_clk_divisor > 0,
                # Last data cycle was already captured in the USER state.
                NextState("SEND_USER_DATA"),
            ).Elif(clkgen.posedge_reg2,
                # Capture last data cycle.
                Case(usr_width, din_width_cases),
                NextState("SEND_USER_DATA"),
            )
        )
        fsm.act("SEND_USER_DATA",
            source.valid.eq(1),
            source.last.eq(1),
            source.data.eq(usr_din),
            If(source.ready,
                NextState("IDLE"),
            )
        )
        fsm.act("SEND_DATA",
            source.valid.eq(1),
            source.last.eq(1),
            source.data.eq(data),
            If(source.ready,
                NextState("IDLE"),
            )
        )
Example #4
0
    def __init__(self, pads, sys_clk_freq=100e6, cl=None):
        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

        # Parameters -------------------------------------------------------------------------------
        cl = get_default_cl(memtype="SDR", tck=1 /
                            sys_clk_freq) if cl is None else cl

        # PHY settings -----------------------------------------------------------------------------
        self.settings = PhySettings(phytype="GENSDRPHY",
                                    memtype="SDR",
                                    databits=databits,
                                    dfi_databits=databits,
                                    nranks=nranks,
                                    nphases=1,
                                    rdphase=0,
                                    wrphase=0,
                                    cl=cl,
                                    read_latency=cl + 1,
                                    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)

            # Commands -----------------------------------------------------------------------------
            commands = {
                "a": "address",
                "ba": "bank",
                "ras_n": "ras_n",
                "cas_n": "cas_n",
                "we_n": "we_n",
            }
            if hasattr(pads, "cke"): commands.update({"cke": "cke"})
            if hasattr(pads, "cs_n"): commands.update({"cs_n": "cs_n"})
            for pad_name, dfi_name in commands.items():
                pad = getattr(pads, pad_name)
                for i in range(len(pad)):
                    self.specials += SDROutput(i=getattr(dfi.p0, dfi_name)[i],
                                               o=pad[i])

        # DQ/DM Data Path --------------------------------------------------------------------------
        for i in range(len(pads.dq)):
            self.specials += SDRTristate(
                io=pads.dq[i],
                o=dfi.p0.wrdata[i],
                oe=dfi.p0.wrdata_en,
                i=dfi.p0.rddata[i],
            )
        if hasattr(pads, "dm"):
            for i in range(len(pads.dm)):
                self.specials += SDROutput(i=dfi.p0.wrdata_en
                                           & dfi.p0.wrdata_mask[i],
                                           o=pads.dm[i])

        # DQ/DM Control Path -----------------------------------------------------------------------
        rddata_en = Signal(self.settings.read_latency)
        self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en))
        self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1])
Example #5
0
    def __init__(self, platform, pads, usb_clk_freq=48e6, dma_data_width=32):
        self.pads = pads
        self.usb_clk_freq = usb_clk_freq
        self.dma_data_width = dma_data_width

        self.wb_ctrl = wb_ctrl = wishbone.Interface(data_width=32)
        self.wb_dma = wb_dma = wishbone.Interface(data_width=dma_data_width)

        self.interrupt = Signal()

        # # #

        usb_ios = Record([
            ("dp_i", 1),
            ("dp_o", 1),
            ("dp_oe", 1),
            ("dm_i", 1),
            ("dm_o", 1),
            ("dm_oe", 1),
        ])

        self.specials += Instance(
            self.get_netlist_name(),
            # Clk / Rst.
            i_phy_clk=ClockSignal("usb"),
            i_phy_reset=ResetSignal("usb"),
            i_ctrl_clk=ClockSignal("sys"),
            i_ctrl_reset=ResetSignal("sys"),

            # Wishbone Control.
            i_io_ctrl_CYC=wb_ctrl.cyc,
            i_io_ctrl_STB=wb_ctrl.stb,
            o_io_ctrl_ACK=wb_ctrl.ack,
            i_io_ctrl_WE=wb_ctrl.we,
            i_io_ctrl_ADR=wb_ctrl.adr,
            o_io_ctrl_DAT_MISO=wb_ctrl.dat_r,
            i_io_ctrl_DAT_MOSI=wb_ctrl.dat_w,
            i_io_ctrl_SEL=wb_ctrl.sel,

            # Wishbone DMA.
            o_io_dma_CYC=wb_dma.cyc,
            o_io_dma_STB=wb_dma.stb,
            i_io_dma_ACK=wb_dma.ack,
            o_io_dma_WE=wb_dma.we,
            o_io_dma_ADR=wb_dma.adr,
            i_io_dma_DAT_MISO=wb_dma.dat_r,
            o_io_dma_DAT_MOSI=wb_dma.dat_w,
            o_io_dma_SEL=wb_dma.sel,
            i_io_dma_ERR=wb_dma.err,
            o_io_dma_CTI=wb_dma.cti,
            o_io_dma_BTE=wb_dma.bte,

            # Interrupt.
            o_io_interrupt=self.interrupt,

            # USB
            i_io_usb_0_dp_read=usb_ios.dp_i,
            o_io_usb_0_dp_write=usb_ios.dp_o,
            o_io_usb_0_dp_writeEnable=usb_ios.dp_oe,
            i_io_usb_0_dm_read=usb_ios.dm_i,
            o_io_usb_0_dm_write=usb_ios.dm_o,
            o_io_usb_0_dm_writeEnable=usb_ios.dm_oe,
        )
        self.specials += SDRTristate(
            io=pads.dp,
            o=usb_ios.dp_o,
            oe=usb_ios.dp_oe,
            i=usb_ios.dp_i,
        )
        self.specials += SDRTristate(
            io=pads.dm,
            o=usb_ios.dm_o,
            oe=usb_ios.dm_oe,
            i=usb_ios.dm_i,
        )

        self.add_sources(platform)
Example #6
0
    def __init__(self, pads, flash, device, clock_domain, default_divisor):
        self.source = source = stream.Endpoint(spi_phy_data_layout)
        self.sink = sink = stream.Endpoint(spi_phy_ctl_layout)
        self.cs_n = Signal()
        self._spi_clk_divisor = spi_clk_divisor = Signal(8)
        self._spi_dummy_bits = spi_dummy_bits = Signal(8)
        self._default_dummy_bits = flash.dummy_bits if flash.fast_mode else 0
        self._default_divisor = default_divisor

        self.clk_divisor = clk_divisor = CSRStorage(
            8, reset=self._default_divisor)
        self.dummy_bits = dummy_bits = CSRStorage(
            8, reset=self._default_dummy_bits)

        # # #

        if clock_domain != "sys":
            self.specials += MultiReg(clk_divisor.storage, spi_clk_divisor,
                                      "litespi")
            self.specials += MultiReg(dummy_bits.storage, spi_dummy_bits,
                                      "litespi")
        else:
            self.comb += spi_clk_divisor.eq(clk_divisor.storage)
            self.comb += spi_dummy_bits.eq(dummy_bits.storage)
        if hasattr(pads, "miso"):
            bus_width = 1
            pads.dq = [pads.mosi, pads.miso]
        else:
            bus_width = len(pads.dq)

        assert bus_width in [1, 2, 4, 8]

        # Check if number of pads matches configured mode.
        assert flash.check_bus_width(bus_width)

        addr_bits = flash.addr_bits
        cmd_width = flash.cmd_width
        addr_width = flash.addr_width
        data_width = flash.bus_width
        command = flash.read_opcode.code
        ddr = flash.ddr

        # For Output modes there is a constant 8 dummy cycles, for I/O and DTR modes there are
        # different number of dummy cycles and in some cases they can be configurable.
        # We control a number of dummy cycles by substracting addr_width value from spi_dummy_bits,
        # so to achieve a proper number of dummy cycles when using shift_out function we need to
        # calculate total dummy bits which depends on addr_width value.
        # NOTE: these values are just default ones, in case chip has different default dummy cycles
        # for these modes or dummy cycles can be configured, please adjust the dummy bits value via
        # CSR in liblitespi accordingly.
        if (addr_width > 1):
            # DTR mode.
            if (ddr):
                if (addr_width == 2):
                    self.default_dummy_bits = 6 * addr_width
                elif (addr_width == 4):
                    self.default_dummy_bits = 8 * addr_width
                else:
                    self.default_dummy_bits = 16 * addr_width
            # I/O mode.
            else:
                if (addr_width == 2):
                    self.default_dummy_bits = 4 * addr_width
                elif (addr_width == 4):
                    self.default_dummy_bits = 6 * addr_width
                else:
                    self.default_dummy_bits = 16 * addr_width

        # Clock Generator.
        self.submodules.clkgen = clkgen = LiteSPIClkGen(pads,
                                                        device,
                                                        with_ddr=ddr)
        self.comb += [
            clkgen.div.eq(spi_clk_divisor),
            clkgen.sample_cnt.eq(1),
            clkgen.update_cnt.eq(1),
            pads.cs_n.eq(self.cs_n),
        ]

        # I/Os.
        data_bits = 32
        cmd_bits = 8

        dq_o = Signal(len(pads.dq))
        dq_i = Signal(len(pads.dq))
        dq_oe = Signal(len(pads.dq))

        for i in range(len(pads.dq)):
            self.specials += SDRTristate(
                io=pads.dq[i],
                o=dq_o[i],
                oe=dq_oe[i],
                i=dq_i[i],
            )

        # FSM.
        self.fsm_cnt = fsm_cnt = Signal(8)
        addr = Signal(addr_bits if not ddr else addr_bits +
                      addr_width)  # Dummy data for the first register shift
        data = Signal(data_bits)
        cmd = Signal(cmd_bits)

        usr_dout = Signal().like(sink.data)
        usr_din = Signal().like(sink.data)
        usr_len = Signal().like(sink.len)
        usr_width = Signal().like(sink.width)
        usr_mask = Signal().like(sink.mask)

        din_width_cases = {1: [NextValue(usr_din, Cat(dq_i[1], usr_din))]}
        for i in [2, 4, 8]:
            din_width_cases[i] = [NextValue(usr_din, Cat(dq_i[0:i], usr_din))]

        dout_width_cases = {}
        for i in [1, 2, 4, 8]:
            dout_width_cases[i] = [dq_o.eq(usr_dout[-i:])]

        commands = {
            CMD: [
                NextValue(addr, sink.data),
                NextValue(cmd, command),
                NextState("CMD")
            ],
            READ: [NextState("DATA")],
            USER: [
                NextValue(usr_dout, sink.data << (32 - sink.len)),
                NextValue(usr_din, 0),
                NextValue(usr_len, sink.len),
                NextValue(usr_width, sink.width),
                NextValue(usr_mask, sink.mask),
                NextState("USER")
            ],
        }

        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE",
            sink.ready.eq(1),
            If(
                sink.valid,
                Case(sink.cmd, commands),
            ),
        )
        fsm.act(
            "CMD",
            dq_oe.eq(cmd_oe_mask),
            dq_o.eq(cmd[-cmd_width:]),
            self.shift_out(
                width=cmd_width,
                bits=cmd_bits,
                next_state="ADDR",
                op=[NextValue(cmd, cmd << cmd_width)],
                trigger=clkgen.negedge,
                ddr=False,
            ),
        )
        fsm.act(
            "ADDR", dq_oe.eq(addr_oe_mask[addr_width]),
            dq_o.eq(addr[-addr_width:]),
            If(
                spi_dummy_bits > 0,
                self.shift_out(
                    width=addr_width,
                    bits=len(addr),
                    next_state="DUMMY",
                    op=[NextValue(addr, addr << addr_width)],
                    trigger=clkgen.negedge if not ddr else clkgen.update,
                    ddr=ddr)).Else(
                        self.shift_out(
                            width=addr_width,
                            bits=len(addr),
                            next_state="IDLE",
                            op=[NextValue(addr, addr << addr_width)],
                            trigger=clkgen.negedge
                            if not ddr else clkgen.update,
                            ddr=ddr)))
        fsm.act(
            "DUMMY",
            If(fsm_cnt < 8, dq_oe.eq(addr_oe_mask[addr_width])
               ),  # output 0's for the first dummy byte
            self.shift_out(width=addr_width,
                           bits=spi_dummy_bits,
                           next_state="IDLE"),
        )
        fsm.act(
            "DATA",
            self.shift_out(
                width=data_width,
                bits=data_bits,
                next_state="SEND_DATA",
                op=[
                    NextValue(
                        data,
                        Cat(dq_i[1] if data_width == 1 else dq_i[0:data_width],
                            data))
                ],
                trigger=clkgen.posedge if not ddr else clkgen.sample,
                ddr=ddr))
        fsm.act(
            "USER",
            dq_oe.eq(usr_mask),
            Case(usr_width, dout_width_cases),
            self.shift_out(
                width=usr_width,
                bits=usr_len,
                next_state="SEND_USER_DATA",
                trigger=[
                    clkgen.posedge,  # data sampling
                    clkgen.negedge,  # data update
                ],
                op=[
                    [Case(usr_width, din_width_cases)],
                    [NextValue(usr_dout, usr_dout << usr_width)],
                ],
                ddr=False)),
        fsm.act("SEND_USER_DATA", source.valid.eq(1), source.last.eq(1),
                source.data.eq(usr_din), If(
                    source.ready,
                    NextState("IDLE"),
                ))
        fsm.act("SEND_DATA", source.valid.eq(1), source.last.eq(1),
                source.data.eq(data), If(
                    source.ready,
                    NextState("IDLE"),
                ))
Example #7
0
    def __init__(self, pads, cl=2, cmd_latency=1):
        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 cl in [2, 3]
        assert databits % 8 == 0

        # PHY settings -----------------------------------------------------------------------------
        self.settings = PhySettings(phytype="GENSDRPHY",
                                    memtype="SDR",
                                    databits=databits,
                                    dfi_databits=databits,
                                    nranks=nranks,
                                    nphases=1,
                                    rdphase=0,
                                    wrphase=0,
                                    rdcmdphase=0,
                                    wrcmdphase=0,
                                    cl=cl,
                                    read_latency=cl + cmd_latency,
                                    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.specials += [
                SDROutput(i=dfi.p0.address[i], o=pads.a[i])
                for i in range(len(pads.a))
            ]
            self.specials += [
                SDROutput(i=dfi.p0.bank[i], o=pads.ba[i])
                for i in range(len(pads.ba))
            ]
            self.specials += SDROutput(i=dfi.p0.cas_n, o=pads.cas_n)
            self.specials += SDROutput(i=dfi.p0.ras_n, o=pads.ras_n)
            self.specials += SDROutput(i=dfi.p0.we_n, o=pads.we_n)
            if hasattr(pads, "cke"):
                self.specials += SDROutput(i=dfi.p0.cke, o=pads.cke)
            if hasattr(pads, "cs_n"):
                self.specials += SDROutput(i=dfi.p0.cs_n, o=pads.cs_n)

        # DQ/DM Data Path --------------------------------------------------------------------------
        for i in range(len(pads.dq)):
            self.specials += SDRTristate(
                io=pads.dq[i],
                o=dfi.p0.wrdata[i],
                oe=dfi.p0.wrdata_en,
                i=dfi.p0.rddata[i],
            )
        if hasattr(pads, "dm"):
            for i in range(len(pads.dm)):
                self.comb += pads.dm[i].eq(0)  # FIXME

        # DQ/DM Control Path -----------------------------------------------------------------------
        rddata_en = Signal(cl + cmd_latency)
        self.sync += rddata_en.eq(Cat(dfi.p0.rddata_en, rddata_en))
        self.sync += dfi.p0.rddata_valid.eq(rddata_en[-1])
Example #8
0
    def __init__(self, pads, flash, device, clock_domain, default_divisor,
                 cs_delay):
        self.source = source = stream.Endpoint(spi_phy2core_layout)
        self.sink = sink = stream.Endpoint(spi_core2phy_layout)
        self.cs = Signal()
        self._spi_clk_divisor = spi_clk_divisor = Signal(8)

        self._default_divisor = default_divisor

        self.clk_divisor = clk_divisor = CSRStorage(
            8, reset=self._default_divisor)

        # # #

        # Resynchronize CSR Clk Divisor to LiteSPI Clk Domain.
        self.submodules += ResyncReg(clk_divisor.storage, spi_clk_divisor,
                                     clock_domain)

        # Determine SPI Bus width and DQs.
        if hasattr(pads, "mosi"):
            bus_width = 1
        else:
            bus_width = len(pads.dq)
        assert bus_width in [1, 2, 4, 8]

        # Check if number of pads matches configured mode.
        assert flash.check_bus_width(bus_width)

        self.addr_bits = addr_bits = flash.addr_bits
        self.cmd_width = cmd_width = flash.cmd_width
        self.addr_width = addr_width = flash.addr_width
        self.data_width = data_width = flash.bus_width
        self.ddr = ddr = flash.ddr

        self.command = command = flash.read_opcode.code

        # Clock Generator.
        self.submodules.clkgen = clkgen = LiteSPIClkGen(pads,
                                                        device,
                                                        with_ddr=ddr)
        self.comb += [
            clkgen.div.eq(spi_clk_divisor),
            clkgen.sample_cnt.eq(1),
            clkgen.update_cnt.eq(1),
        ]

        # CS control.
        cs_timer = WaitTimer(cs_delay +
                             1)  # Ensure cs_delay cycles between XFers.
        cs_enable = Signal()
        self.submodules += cs_timer
        self.comb += cs_timer.wait.eq(self.cs)
        self.comb += cs_enable.eq(cs_timer.done)
        self.comb += pads.cs_n.eq(~cs_enable)

        # I/Os.
        data_bits = 32
        cmd_bits = 8

        if hasattr(pads, "mosi"):
            dq_o = Signal()
            dq_i = Signal(2)
            dq_oe = Signal()  # Unused.
            self.specials += SDROutput(i=dq_o, o=pads.mosi)
            self.specials += SDRInput(i=pads.miso, o=dq_i[1])
        else:
            dq_o = Signal(len(pads.dq))
            dq_i = Signal(len(pads.dq))
            dq_oe = Signal(len(pads.dq))
            for i in range(len(pads.dq)):
                self.specials += SDRTristate(
                    io=pads.dq[i],
                    o=dq_o[i],
                    oe=dq_oe[i],
                    i=dq_i[i],
                )

        # Data Shift Registers.
        sr_cnt = Signal(8, reset_less=True)
        sr_out_load = Signal()
        sr_out_shift = Signal()
        sr_out = Signal(len(sink.data), reset_less=True)
        sr_in_shift = Signal()
        sr_in = Signal(len(sink.data), reset_less=True)

        # Data Out Generation/Load/Shift.
        self.comb += [
            dq_oe.eq(sink.mask),
            Case(
                sink.width, {
                    1: dq_o.eq(sr_out[-1:]),
                    2: dq_o.eq(sr_out[-2:]),
                    4: dq_o.eq(sr_out[-4:]),
                    8: dq_o.eq(sr_out[-8:]),
                })
        ]
        self.sync += If(sr_out_load,
                        sr_out.eq(sink.data << (len(sink.data) - sink.len)))
        self.sync += If(
            sr_out_shift,
            Case(
                sink.width, {
                    1: sr_out.eq(Cat(Signal(1), sr_out)),
                    2: sr_out.eq(Cat(Signal(2), sr_out)),
                    4: sr_out.eq(Cat(Signal(4), sr_out)),
                    8: sr_out.eq(Cat(Signal(8), sr_out)),
                }))

        # Data In Shift.
        self.sync += If(
            sr_in_shift,
            Case(
                sink.width, {
                    1: sr_in.eq(Cat(dq_i[1], sr_in)),
                    2: sr_in.eq(Cat(dq_i[:2], sr_in)),
                    4: sr_in.eq(Cat(dq_i[:4], sr_in)),
                    8: sr_in.eq(Cat(dq_i[:8], sr_in)),
                }))

        # FSM.
        self.submodules.fsm = fsm = FSM(reset_state="WAIT-CMD-DATA")
        fsm.act(
            "WAIT-CMD-DATA",
            # Wait for CS and a CMD from the Core.
            If(
                cs_enable & sink.valid,
                # Load Shift Register Count/Data Out.
                NextValue(sr_cnt, sink.len - sink.width),
                sr_out_load.eq(1),
                # Start XFER.
                NextState("XFER"),
            ),
        )
        fsm.act(
            "XFER",
            # Generate Clk.
            self.clkgen.en.eq(1),

            # Data In Shift.
            If(clkgen.posedge_reg2, sr_in_shift.eq(1)),

            # Data Out Shift.
            If(clkgen.negedge, sr_out_shift.eq(1)),

            # Shift Register Count Update/Check.
            If(
                self.clkgen.negedge,
                NextValue(sr_cnt, sr_cnt - sink.width),
                # End XFer.
                If(
                    sr_cnt == 0,
                    NextState("XFER-END"),
                ),
            ),
        )
        fsm.act(
            "XFER-END",
            # Last data already captured in XFER when divisor > 0 so only capture for divisor == 0.
            If(
                (spi_clk_divisor > 0) | clkgen.posedge_reg2,
                # Accept CMD.
                sink.ready.eq(1),
                # Capture last data (only for spi_clk_divisor == 0).
                sr_in_shift.eq(spi_clk_divisor == 0),
                # Send Status/Data to Core.
                NextState("SEND-STATUS-DATA"),
            ))
        self.comb += source.data.eq(sr_in)
        fsm.act(
            "SEND-STATUS-DATA",
            # Send Data In to Core and return to WAIT when accepted.
            source.valid.eq(1),
            source.last.eq(1),
            If(
                source.ready,
                NextState("WAIT-CMD-DATA"),
            ))
Example #9
0
    def __init__(self, pads, clk_freq,
        fifo_depth = 64,
        read_time  = 128,
        write_time = 128):
        self.dw     = dw = len(pads.data)
        self.pads   = pads
        self.sink   = stream.Endpoint(phy_description(dw))
        self.source = stream.Endpoint(phy_description(dw))

        # # #

        # Pads Reset.
        # -----------
        pads.oe_n.reset = 1
        pads.rd_n.reset = 1
        pads.wr_n.reset = 1

        # Read CDC/FIFO (FTDI --> SoC).
        # -----------------------------
        self.submodules.read_cdc  = stream.ClockDomainCrossing(phy_description(dw),
            cd_from         = "usb",
            cd_to           = "sys",
            with_common_rst = True
        )
        self.submodules.read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth)
        self.comb += self.read_cdc.source.connect(self.read_fifo.sink)
        self.comb += self.read_fifo.source.connect(self.source)
        read_fifo_almost_full = (self.read_fifo.level > (fifo_depth - 4))
        read_fifo_almost_full_usb = Signal()
        self.specials += MultiReg(read_fifo_almost_full, read_fifo_almost_full_usb)

        # Write FIFO/CDC (SoC --> FTDI).
        # ------------------------------
        self.submodules.write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth)
        self.submodules.write_cdc  = stream.ClockDomainCrossing(phy_description(dw),
            cd_from         = "sys",
            cd_to           = "usb",
            with_common_rst = True
        )
        self.comb += self.sink.connect(self.write_fifo.sink)
        self.comb += self.write_fifo.source.connect(self.write_cdc.sink)

        # Read / Write Anti-Starvation.
        # -----------------------------
        read_time_en,  max_read_time  = anti_starvation(self, read_time)
        write_time_en, max_write_time = anti_starvation(self, write_time)

        # Read / Write Detection.
        # -----------------------
        self.wants_write = wants_write = Signal()
        self.wants_read  = wants_read  = Signal()
        self.comb += [
            wants_write.eq(~pads.txe_n & self.write_cdc.source.valid),
            wants_read.eq( ~pads.rxf_n & (self.read_cdc.sink.ready & ~read_fifo_almost_full_usb)),
        ]

        # Data Bus Tristate.
        # ------------------
        self.data_w  = data_w  = Signal(dw)
        self.data_r  = data_r  = Signal(dw)
        self.data_oe = data_oe = Signal()
        for i in range(dw):
            self.specials += SDRTristate(
                io  = pads.data[i],
                o   = data_w[i],
                oe  = data_oe,
                i   = data_r[i],
                clk = ClockSignal("usb")
            )
        if hasattr(pads, "be"):
            for i in range(dw//8):
                self.specials += SDRTristate(
                    io  = pads.be[i],
                    o   = Signal(reset=0b1),
                    oe  = data_oe,
                    i   = Signal(),
                    clk = ClockSignal("usb")
                )

        # Read / Write FSM.
        # -----------------
        fsm = FSM(reset_state="READ")
        fsm = ClockDomainsRenamer("usb")(fsm)
        self.submodules.fsm = fsm
        fsm.act("READ",
            # Arbitration.
            read_time_en.eq(1),
            If(wants_write,
                If(~wants_read | max_read_time,
                    NextState("READ-TO-WRITE")
                )
            ),
            # Control/Data-Path.
            data_oe.eq(0),
            NextValue(pads.oe_n, ~wants_read),
            NextValue(pads.rd_n, pads.oe_n | ~wants_read),
            NextValue(pads.wr_n, 1),
        )
        self.comb += self.read_cdc.sink.data.eq(data_r)
        self.sync.usb += self.read_cdc.sink.valid.eq(~pads.rd_n & ~pads.rxf_n)

        fsm.act("READ-TO-WRITE",
            NextState("WRITE")
        )
        fsm.act("WRITE",
            # Arbitration.
            write_time_en.eq(1),
            If(wants_read,
                If(~wants_write | max_write_time,
                    NextState("WRITE-TO-READ")
                )
            ),
            # Control/Data-Path.
            data_oe.eq(1),
            NextValue(pads.oe_n, 1),
            NextValue(pads.rd_n, 1),
            NextValue(pads.wr_n, ~wants_write),
            #data_w.eq(write_fifo.source.data),
            NextValue(data_w, self.write_cdc.source.data), # FIXME: Add 1 cycle delay.
            self.write_cdc.source.ready.eq(wants_write),
        )
        fsm.act("WRITE-TO-READ",
            NextState("READ")
        )