connect SDRAM dqm to wrdata_mask
[soc.git] / src / soc / litex / florent / ls180soc.py
index 877abf020f6d4e059b9ff6e6cedb68688024b11b..cd8119ebba7ce080cf17a6c147db92edbedd27f5 100755 (executable)
@@ -2,8 +2,11 @@
 
 import os
 import argparse
+from functools import reduce
+from operator import or_
 
-from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState)
+from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState,
+                   Cat, Record, ClockSignal, wrap, ResetInserter)
 
 from litex.build.generic_platform import Pins, Subsignal
 from litex.build.sim import SimPlatform
@@ -18,11 +21,13 @@ from litex.soc.integration.common import get_mem_data
 
 from litedram import modules as litedram_modules
 from litedram.phy.model import SDRAMPHYModel
-from litedram.phy.gensdrphy import GENSDRPHY, HalfRateGENSDRPHY
-
-from litex.soc.cores.gpio import GPIOInOut, GPIOIn, GPIOOut#, GPIOTristate
+#from litedram.phy.gensdrphy import GENSDRPHY, HalfRateGENSDRPHY
+from litedram.common import PHYPadsCombiner, PhySettings
+from litedram.phy.dfi import Interface as DFIInterface
 from litex.soc.cores.spi import SPIMaster
 from litex.soc.cores.pwm import PWM
+from litex.soc.cores.bitbang import I2CMaster
+from litex.soc.cores import uart
 
 from litex.tools.litex_sim import sdram_module_nphases, get_sdram_phy_settings
 
@@ -39,8 +44,196 @@ from microwatt import Microwatt
 from litex.soc.integration.soc import SoCCSRHandler
 SoCCSRHandler.supported_address_width.append(12)
 
+# GPIO Tristate -------------------------------------------------------
+# doesn't work properly.
+#from litex.soc.cores.gpio import GPIOTristate
+from litex.soc.interconnect.csr import CSRStorage, CSRStatus
+from migen.genlib.cdc import MultiReg
+
+# Imports
+from litex.soc.interconnect import wishbone
+from litesdcard.phy import (SDPHY, SDPHYClocker,
+                            SDPHYInit, SDPHYCMDW, SDPHYCMDR,
+                            SDPHYDATAW, SDPHYDATAR,
+                            _sdpads_layout)
+from litesdcard.core import SDCore
+from litesdcard.frontend.dma import SDBlock2MemDMA, SDMem2BlockDMA
+from litex.build.io import SDROutput, SDRInput
+
+
+class GPIOTristateASIC(Module, AutoCSR):
+    def __init__(self, pads):
+        nbits     = len(pads.oe) # hack
+        self._oe  = CSRStorage(nbits, description="GPIO Tristate(s) Control.")
+        self._in  = CSRStatus(nbits,  description="GPIO Input(s) Status.")
+        self._out = CSRStorage(nbits, description="GPIO Ouptut(s) Control.")
+
+        # # #
+
+        _pads = Record( (("i",  nbits),
+                         ("o",  nbits),
+                         ("oe", nbits)))
+        self.comb += _pads.i.eq(pads.i)
+        self.comb += pads.o.eq(_pads.o)
+        self.comb += pads.oe.eq(_pads.oe)
+
+        self.comb += _pads.oe.eq(self._oe.storage)
+        self.comb += _pads.o.eq(self._out.storage)
+        for i in range(nbits):
+            self.specials += MultiReg(_pads.i[i], self._in.status[i])
+
+# SDCard PHY IO -------------------------------------------------------
+
+class SDRPad(Module):
+    def __init__(self, pad, name, o, oe, i):
+        clk = ClockSignal()
+        _o = getattr(pad, "%s_o" % name)
+        _oe = getattr(pad, "%s_oe" % name)
+        _i = getattr(pad, "%s_i" % name)
+        self.specials += SDROutput(clk=clk, i=oe, o=_oe)
+        for j in range(len(_o)):
+            self.specials += SDROutput(clk=clk, i=o[j], o=_o[j])
+            self.specials += SDRInput(clk=clk, i=_i[j], o=i[j])
+
+
+class SDPHYIOGen(Module):
+    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
+        c = sdpads.cmd
+        self.submodules.sd_cmd = SDRPad(pads, "cmd", c.o, c.oe, c.i)
+
+        # Data
+        d = sdpads.data
+        self.submodules.sd_data = SDRPad(pads, "data", d.o, d.oe, d.i)
+
+
+class SDPHY(Module, AutoCSR):
+    def __init__(self, pads, device, sys_clk_freq,
+                 cmd_timeout=10e-3, data_timeout=10e-3):
+        self.card_detect = CSRStatus() # Assume SDCard is present if no cd pin.
+        self.comb += self.card_detect.status.eq(getattr(pads, "cd", 0))
+
+        self.submodules.clocker = clocker = SDPHYClocker()
+        self.submodules.init    = init    = SDPHYInit()
+        self.submodules.cmdw    = cmdw    = SDPHYCMDW()
+        self.submodules.cmdr    = cmdr    = SDPHYCMDR(sys_clk_freq,
+                                                      cmd_timeout, cmdw)
+        self.submodules.dataw   = dataw   = SDPHYDATAW()
+        self.submodules.datar   = datar   = SDPHYDATAR(sys_clk_freq,
+                                                      data_timeout)
+
+        # # #
+
+        self.sdpads = sdpads = Record(_sdpads_layout)
+
+        # IOs
+        sdphy_cls = SDPHYIOGen
+        self.submodules.io = sdphy_cls(clocker, sdpads, pads)
+
+        # Connect pads_out of submodules to physical pads --------------
+        pl = [init, cmdw, cmdr, dataw, datar]
+        self.comb += [
+            sdpads.clk.eq(    reduce(or_, [m.pads_out.clk     for m in pl])),
+            sdpads.cmd.oe.eq( reduce(or_, [m.pads_out.cmd.oe  for m in pl])),
+            sdpads.cmd.o.eq(  reduce(or_, [m.pads_out.cmd.o   for m in pl])),
+            sdpads.data.oe.eq(reduce(or_, [m.pads_out.data.oe for m in pl])),
+            sdpads.data.o.eq( reduce(or_, [m.pads_out.data.o  for m in pl])),
+        ]
+        for m in pl:
+            self.comb += m.pads_out.ready.eq(self.clocker.ce)
+
+        # Connect physical pads to pads_in of submodules ---------------
+        for m in pl:
+            self.comb += m.pads_in.valid.eq(self.clocker.ce)
+            self.comb += m.pads_in.cmd.i.eq(sdpads.cmd.i)
+            self.comb += m.pads_in.data.i.eq(sdpads.data.i)
+
+        # Speed Throttling -------------------------------------------
+        self.comb += clocker.stop.eq(dataw.stop | datar.stop)
+
+
+# Generic SDR PHY ---------------------------------------------------------
+
+class GENSDRPHY(Module):
+    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_i)
+        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 = DFIInterface(addressbits, bankbits, nranks, databits)
+
+        # # #
+
+        # Iterate on pads groups ------------------------------------------
+        for pads_group in range(len(pads.groups)):
+            pads.sel_group(pads_group)
+
+            # Addresses and Commands --------------------------------------
+            p0 = dfi.p0
+            self.specials += [SDROutput(i=p0.address[i], o=pads.a[i])
+                                    for i in range(len(pads.a))]
+            self.specials += [SDROutput(i=p0.bank[i], o=pads.ba[i])
+                                    for i in range(len(pads.ba))]
+            self.specials += SDROutput(i=p0.cas_n, o=pads.cas_n)
+            self.specials += SDROutput(i=p0.ras_n, o=pads.ras_n)
+            self.specials += SDROutput(i=p0.we_n, o=pads.we_n)
+            if hasattr(pads, "cke"):
+                for i in range(len(pads.cke)):
+                        self.specials += SDROutput(i=p0.cke[i], o=pads.cke[i])
+            if hasattr(pads, "cs_n"):
+                for i in range(len(pads.cs_n)):
+                    self.specials += SDROutput(i=p0.cs_n[i], o=pads.cs_n[i])
 
-# LibreSoCSim -----------------------------------------------------------------
+        # DQ/DM Data Path -------------------------------------------------
+
+        d = dfi.p0
+        wren = []
+        self.submodules.dq = SDRPad(pads, "dq", d.wrdata, d.wrdata_en, d.rddata)
+
+        if hasattr(pads, "dm"):
+            for i in range(len(pads.dm)):
+                self.specials += SDROutput(i=d.wrdata_mask[i], o=pads.dm[i])
+
+        # 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])
+
+
+# LibreSoC 180nm ASIC -------------------------------------------------------
 
 class LibreSoCSim(SoCCore):
     def __init__(self, cpu="libresoc", debug=False, with_sdram=True,
@@ -59,7 +252,7 @@ class LibreSoCSim(SoCCore):
             uart_name = "sim"
         elif platform == 'ls180':
             platform     = LS180Platform()
-            uart_name = "serial"
+            uart_name = "uart"
 
         #cpu_data_width = 32
         cpu_data_width = 64
@@ -100,7 +293,8 @@ class LibreSoCSim(SoCCore):
             cpu_variant              = variant,
             csr_data_width            = 8,
             l2_size             = 0,
-            uart_name                = uart_name,
+            with_uart                = False,
+            uart_name                = None,
             with_sdram               = with_sdram,
             sdram_module          = sdram_module,
             sdram_data_width      = sdram_data_width,
@@ -145,7 +339,7 @@ class LibreSoCSim(SoCCore):
                             memtype    = sdram_module.memtype,
                             data_width = sdram_data_width,
                             clk_freq   = sdram_clk_freq)
-            #sdrphy_cls = HalfRateGENSDRPHY 
+            #sdrphy_cls = HalfRateGENSDRPHY
             sdrphy_cls = GENSDRPHY
             self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"))
             #self.submodules.sdrphy = sdrphy_cls(sdram_module,
@@ -156,7 +350,7 @@ class LibreSoCSim(SoCCore):
                 phy                     = self.sdrphy,
                 module                  = sdram_module,
                 origin                  = self.mem_map["main_ram"],
-                size                    = 0x40000000,
+                size                    = 0x80000000,
                 l2_cache_size           = 0, # 8192
                 l2_cache_min_data_width = 128,
                 l2_cache_reverse        = True
@@ -169,16 +363,41 @@ class LibreSoCSim(SoCCore):
             self.add_constant("MEMTEST_ADDR_DEBUG", 1)
             self.add_constant("MEMTEST_DATA_DEBUG", 1)
 
-        # GPIOs
-        #platform.add_extension([("gpio_in", 0, Pins(8))])
-        self.submodules.gpio_in = GPIOIn(platform.request("gpio_in"))
-        self.add_csr("gpio_in")
-        self.submodules.gpio_out = GPIOIn(platform.request("gpio_out"))
-        self.add_csr("gpio_out")
-
-        if False:
-            self.submodules.gpio = GPIOTristate(platform.request("gpio"))
-            self.add_csr("gpio")
+            # SDRAM clock
+            sys_clk = ClockSignal()
+            sdr_clk = platform.request("sdram_clock")
+            #self.specials += DDROutput(1, 0, , sdram_clk)
+            self.specials += SDROutput(clk=sys_clk, i=sys_clk, o=sdr_clk)
+
+        # UART
+        uart_core_pads = self.cpu.cpupads['uart']
+        self.submodules.uart_phy = uart.UARTPHY(
+                pads     = uart_core_pads,
+                clk_freq = self.sys_clk_freq,
+                baudrate = 115200)
+        self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy,
+                tx_fifo_depth = 16,
+                rx_fifo_depth = 16))
+        # "real" pads connect to C4M JTAG iopad
+        uart_pads     = platform.request(uart_name) # "real" (actual) pin
+        uart_io_pads = self.cpu.iopads['uart'] # C4M JTAG pads
+        self.comb += uart_pads.tx.eq(uart_io_pads.tx)
+        self.comb += uart_io_pads.rx.eq(uart_pads.rx)
+
+        self.csr.add("uart_phy", use_loc_if_exists=True)
+        self.csr.add("uart", use_loc_if_exists=True)
+        self.irq.add("uart", use_loc_if_exists=True)
+
+        # GPIOs (bi-directional)
+        gpio_core_pads = self.cpu.cpupads['gpio']
+        self.submodules.gpio = GPIOTristateASIC(gpio_core_pads)
+        self.add_csr("gpio")
+
+        gpio_pads = platform.request("gpio") # "real" (actual) pins
+        gpio_io_pads = self.cpu.iopads['gpio'] # C4M JTAG pads
+        self.comb += gpio_io_pads.i.eq(gpio_pads.i)
+        self.comb += gpio_pads.o.eq(gpio_io_pads.o)
+        self.comb += gpio_pads.oe.eq(gpio_io_pads.oe)
 
         # SPI Master
         self.submodules.spi_master = SPIMaster(
@@ -199,12 +418,58 @@ class LibreSoCSim(SoCCore):
         self.comb += self.cpu.jtag_tdi.eq(jtagpads.tdi)
         self.comb += jtagpads.tdo.eq(self.cpu.jtag_tdo)
 
+        # NC - allows some iopads to be connected up
+        # sigh, just do something, anything, to stop yosys optimising these out
+        nc_pads = platform.request("nc")
+        num_nc = len(nc_pads)
+        self.nc = Signal(num_nc)
+        self.comb += self.nc.eq(nc_pads)
+        self.dummy = Signal(num_nc)
+        for i in range(num_nc):
+            self.sync += self.dummy[i].eq(self.nc[i] | self.cpu.interrupt[0])
+
         # PWM
         for i in range(2):
             name = "pwm%d" % i
             setattr(self.submodules, name, PWM(platform.request("pwm", i)))
             self.add_csr(name)
 
+        if False: # TODO: convert to _i _o _oe
+            # I2C Master
+            self.submodules.i2c = I2CMaster(platform.request("i2c"))
+            self.add_csr("i2c")
+
+        # SDCard -----------------------------------------------------
+
+        # Emulator / Pads
+        sdcard_pads = self.platform.request("sdcard")
+
+        # Core
+        self.submodules.sdphy  = SDPHY(sdcard_pads,
+                                       self.platform.device, self.clk_freq)
+        self.submodules.sdcore = SDCore(self.sdphy)
+        self.add_csr("sdphy")
+        self.add_csr("sdcore")
+
+        # Block2Mem DMA
+        bus = wishbone.Interface(data_width=self.bus.data_width,
+                                 adr_width=self.bus.address_width)
+        self.submodules.sdblock2mem = SDBlock2MemDMA(bus=bus,
+                                    endianness=self.cpu.endianness)
+        self.comb += self.sdcore.source.connect(self.sdblock2mem.sink)
+        dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
+        dma_bus.add_master("sdblock2mem", master=bus)
+        self.add_csr("sdblock2mem")
+
+        # Mem2Block DMA
+        bus = wishbone.Interface(data_width=self.bus.data_width,
+                                 adr_width=self.bus.address_width)
+        self.submodules.sdmem2block = SDMem2BlockDMA(bus=bus,
+                                            endianness=self.cpu.endianness)
+        self.comb += self.sdmem2block.source.connect(self.sdcore.sink)
+        dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus
+        dma_bus.add_master("sdmem2block", master=bus)
+        self.add_csr("sdmem2block")
 
         # Debug ---------------------------------------------------------------
         if not debug:
@@ -493,7 +758,6 @@ def main():
     if args.platform == 'ls180':
         soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
                           platform=args.platform)
-        soc.add_sdcard()
         soc.add_spi_sdcard()
         builder = Builder(soc, compile_gateware = True)
         builder.build(run         = True)