add PLL clock loop-back into CPU
[libresoc-litex.git] / ls180soc.py
index 3224f6d1b1ceb3a441561f726352d44c9f8395c2..a24083977bc4123de781c606d90f9740d340ccc9 100755 (executable)
@@ -43,6 +43,7 @@ from microwatt import Microwatt
 # HACK!
 from litex.soc.integration.soc import SoCCSRHandler
 SoCCSRHandler.supported_address_width.append(12)
+SoCCSRHandler.supported_address_width.append(13)
 
 # GPIO Tristate -------------------------------------------------------
 # doesn't work properly.
@@ -99,27 +100,40 @@ class I2CMaster(Module, AutoCSR):
 
 
 class GPIOTristateASIC(Module, AutoCSR):
-    def __init__(self, pads, prange=None):
-        nbits     = len(pads.oe) # hack
+    def __init__(self, name, pads, prange=None):
+        if prange is None:
+            prange = range(nbits)
+        nbits     = len(prange)
+
         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)
+        _pads = Record( ((name+"i",  nbits),
+                         (name+"o",  nbits),
+                         (name+"oe", nbits)))
+        _o = getattr(_pads, name+"o")
+        _oe = getattr(_pads, name+"oe")
+        _i = getattr(_pads, name+"i")
+        for j, i in enumerate(prange):
+            self.comb += _i[j].eq(pads.i[i])
+            self.comb += pads.o[i].eq(_o[j])
+            self.comb += pads.oe[i].eq(_oe[j])
 
-        self.comb += _pads.oe.eq(self._oe.storage)
-        self.comb += _pads.o.eq(self._out.storage)
-        if prange is None:
-            prange = range(nbits)
-        for i in prange:
-            self.specials += MultiReg(_pads.i[i], self._in.status[i])
+        clk = ClockSignal()
+        o = self._out.storage
+        oe = self._oe.storage
+        i = self._in.status
+        for j in range(nbits):
+            self.specials += SDROutput(clk=clk, i=oe[j], o=_oe[j])
+            self.specials += SDROutput(clk=clk, i=o[j], o=_o[j])
+            self.specials += SDRInput(clk=clk, i=_i[j], o=i[j])
+        #for i in range(nbits):
+            #self.comb += _pads.oe[i].eq(self._oe.storage[i])
+            #self.comb += _pads.o[i].eq(self._out.storage[i])
+            #self.specials += MultiReg(_pads.i[i], self._in.status[i])
 
 # SDCard PHY IO -------------------------------------------------------
 
@@ -129,8 +143,8 @@ class SDRPad(Module):
         _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=oe, o=_oe[j])
             self.specials += SDROutput(clk=clk, i=o[j], o=_o[j])
             self.specials += SDRInput(clk=clk, i=_i[j], o=i[j])
 
@@ -263,8 +277,10 @@ class GENSDRPHY(Module):
         self.submodules.dq = SDRPad(pads, "dq", d.wrdata, d.wrdata_en, d.rddata)
 
         if hasattr(pads, "dm"):
+            print ("sdr pads dm len", pads.dm, len(pads.dm))
             for i in range(len(pads.dm)):
-                self.specials += SDROutput(i=d.wrdata_mask[i], o=pads.dm[i])
+                self.specials += SDROutput(i=d.wrdata_en&d.wrdata_mask[i],
+                                           o=pads.dm[i])
 
         # DQ/DM Control Path ----------------------------------------------
         rddata_en = Signal(cl + cmd_latency)
@@ -282,25 +298,34 @@ class LibreSoCSim(SoCCore):
             sdram_data_width      = 16,
             irq_reserved_irqs = {'uart': 0},
             platform='sim',
+            dff_srams=5,
+            srams_4k=False,
             ):
         assert cpu in ["libresoc", "microwatt"]
         sys_clk_freq = int(50e6)
 
+        platform_name = platform
         if platform == 'sim':
             platform     = Platform()
+            self.platform.name = 'ls180'
             uart_name = "sim"
-        elif platform == 'ls180':
+        elif 'ls180' in platform:
             platform     = LS180Platform()
             uart_name = "uart"
 
         #cpu_data_width = 32
         cpu_data_width = 64
 
-        variant = "ls180"
+        if srams_4k:
+            variant = "ls180sram4k"
+        else:
+            variant = "ls180nopll"
+
+        print ("CPU, variant", platform_name, variant)
 
         # reserve XICS ICP and XICS memory addresses.
-        self.mem_map['icp']  = 0xc0010000
-        self.mem_map['ics']  = 0xc0011000
+        self.mem_map['xics_icp']  = 0xc0010000
+        self.mem_map['xics_ics']  = 0xc0011000
         #self.csr_map["icp"] = 8  #  8 x 0x800 == 0x4000
         #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
 
@@ -320,11 +345,19 @@ class LibreSoCSim(SoCCore):
             self.csr_map["uart"] = 4
 
         self.mem_map["main_ram"] = 0x90000000
-        self.mem_map["sram"] = 0x00000000
-        self.mem_map["sram1"] = 0x00000200
-        self.mem_map["sram2"] = 0x00000400
-        self.mem_map["sram3"] = 0x00000600
-        self.mem_map["sram4"] = 0x00000800
+        if dff_srams == 5:
+            self.mem_map["sram"] = 0x00000000
+            self.mem_map["sram1"] = 0x00000200
+            self.mem_map["sram2"] = 0x00000400
+            self.mem_map["sram3"] = 0x00000600
+            self.mem_map["sram4"] = 0x00000800
+            sram_size = 0x200
+        else:
+            sram_size = 0x80 # ridiculously small
+            if "sram4k" not in variant:
+                sram_size = 0x200 # no 4k SRAMs, make slightly bigger
+            self.mem_map["sram"] = 0x00000000
+            self.mem_map["sram1"] = 0x00000700
         self.mem_map["sram4k_0"] = 0x00001000
         self.mem_map["sram4k_1"] = 0x00002000
         self.mem_map["sram4k_2"] = 0x00003000
@@ -335,8 +368,8 @@ class LibreSoCSim(SoCCore):
             cpu_type                 = "microwatt",
             cpu_cls                  = LibreSoC   if cpu == "libresoc" \
                                        else Microwatt,
-            bus_data_width           = 64,
-            csr_address_width        = 14, # limit to 0x8000
+            #bus_data_width           = 64, # don't add this! stops conversion
+            csr_address_width        = 13, # limit to 0x8000
             cpu_variant              = variant,
             csr_data_width            = 8,
             l2_size             = 0,
@@ -347,18 +380,22 @@ class LibreSoCSim(SoCCore):
             sdram_data_width      = sdram_data_width,
             integrated_rom_size      = 0, # if ram_fname else 0x10000,
             #integrated_sram_size     = 0x1000, - problem with yosys ABC
-            integrated_sram_size     = 0x200,
+            integrated_sram_size     = sram_size,
             #integrated_main_ram_init  = ram_init,
             integrated_main_ram_size = 0x00000000 if with_sdram \
                                         else 0x10000000 , # 256MB
             )
-        self.platform.name = "ls180"
 
-        # add 4 more 4k integrated SRAMs
-        self.add_ram("sram1", self.mem_map["sram1"], 0x200)
-        self.add_ram("sram2", self.mem_map["sram2"], 0x200)
-        self.add_ram("sram3", self.mem_map["sram3"], 0x200)
-        self.add_ram("sram4", self.mem_map["sram4"], 0x200)
+        self.platform.name = platform_name
+
+        if dff_srams == 5:
+            # add 4 more 4k integrated SRAMs
+            self.add_ram("sram1", self.mem_map["sram1"], 0x200)
+            self.add_ram("sram2", self.mem_map["sram2"], 0x200)
+            self.add_ram("sram3", self.mem_map["sram3"], 0x200)
+            self.add_ram("sram4", self.mem_map["sram4"], 0x200)
+        else:
+            self.add_ram("sram1", self.mem_map["sram1"], 0x80) # tiny!
 
         # SDR SDRAM ----------------------------------------------
         if False: # not self.integrated_main_ram_size:
@@ -366,12 +403,12 @@ class LibreSoCSim(SoCCore):
 
         if cpu == "libresoc":
             # XICS interrupt devices
-            icp_addr = self.mem_map['icp']
+            icp_addr = self.mem_map['xics_icp']
             icp_wb = self.cpu.xics_icp
             icp_region = SoCRegion(origin=icp_addr, size=0x20, cached=False)
             self.bus.add_slave(name='icp', slave=icp_wb, region=icp_region)
 
-            ics_addr = self.mem_map['ics']
+            ics_addr = self.mem_map['xics_ics']
             ics_wb = self.cpu.xics_ics
             ics_region = SoCRegion(origin=ics_addr, size=0x1000, cached=False)
             self.bus.add_slave(name='ics', slave=ics_wb, region=ics_region)
@@ -387,14 +424,16 @@ class LibreSoCSim(SoCCore):
         self.submodules.crg = CRG(platform.request("sys_clk"),
                                   platform.request("sys_rst"))
 
-        # PLL/Clock Select
-        clksel_i = platform.request("sys_clksel_i")
-        pll18_o = platform.request("sys_pll_18_o")
-        pll_lck_o = platform.request("sys_pll_lck_o")
+        if hasattr(self.cpu, "clk_sel"):
+            # PLL/Clock Select
+            clksel_i = platform.request("sys_clksel_i")
+            pll_test_o = platform.request("sys_pll_testout_o")
+            pll_vco_o = platform.request("sys_pll_vco_o")
 
-        self.comb += self.cpu.clk_sel.eq(clksel_i) # allow clock src select
-        self.comb += pll18_o.eq(self.cpu.pll_18_o) # "test feed" from the PLL
-        self.comb += pll_lck_o.eq(self.cpu.pll_lck_o) # PLL lock flag
+            self.comb += self.cpu.clk_sel.eq(clksel_i) # allow clock src select
+            self.comb += pll_test_o.eq(self.cpu.pll_test_o) # "test" from PLL
+            self.comb += pll_vco_o.eq(self.cpu.pll_vco_o) # PLL lock flag
+            self.comb += self.cpu.clk.eq(self.cpu.pllclk_o) # PLL out into cpu
 
         #ram_init = []
 
@@ -436,7 +475,8 @@ class LibreSoCSim(SoCCore):
 
             # SDRAM clock
             sys_clk = ClockSignal()
-            sdr_clk = self.cpu.cpupads['sdram_clock']
+            #sdr_clk = self.cpu.cpupads['sdram_clock']
+            sdr_clk = sdram_pads.clock
             #self.specials += DDROutput(1, 0, , sdram_clk)
             self.specials += SDROutput(clk=sys_clk, i=sys_clk, o=sdr_clk)
 
@@ -456,34 +496,40 @@ class LibreSoCSim(SoCCore):
 
         # GPIOs (bi-directional)
         gpio_core_pads = self.cpu.cpupads['gpio']
-        self.submodules.gpio = GPIOTristateASIC(gpio_core_pads, range(8))
-        self.add_csr("gpio")
+        self.submodules.gpio0 = GPIOTristateASIC("gpio0", gpio_core_pads,
+                                                 range(8))
+        self.add_csr("gpio0")
 
-        self.submodules.gpio = GPIOTristateASIC(gpio_core_pads, range(8,16))
+        self.submodules.gpio1 = GPIOTristateASIC("gpio1", gpio_core_pads,
+                                                 range(8, 16))
         self.add_csr("gpio1")
 
         # SPI Master
         print ("cpupadkeys", self.cpu.cpupads.keys())
-        self.submodules.spimaster = SPIMaster(
-            pads         = self.cpu.cpupads['mspi1'],
-            data_width   = 8,
-            sys_clk_freq = sys_clk_freq,
-            spi_clk_freq = 8e6,
-        )
-        self.add_csr("spimaster")
-
-        # SPI SDCard (1 wide)
-        spi_clk_freq = 400e3
-        pads = self.cpu.cpupads['mspi0']
-        spisdcard = SPIMaster(pads, 8, self.sys_clk_freq, spi_clk_freq)
-        spisdcard.add_clk_divider()
-        setattr(self.submodules, 'spisdcard', spisdcard)
-        self.add_csr('spisdcard')
+        if hasattr(self.cpu.cpupads, 'mspi0'):
+            sd_clk_freq = 8e6
+            pads = self.cpu.cpupads['mspi0']
+            spimaster = SPIMaster(pads, 8, self.sys_clk_freq, sd_clk_freq)
+            spimaster.add_clk_divider()
+            setattr(self.submodules, 'spimaster', spimaster)
+            self.add_csr('spimaster')
+
+        if hasattr(self.cpu.cpupads, 'mspi1'):
+            # SPI SDCard (1 wide)
+            spi_clk_freq = 400e3
+            pads = self.cpu.cpupads['mspi1']
+            spisdcard = SPIMaster(pads, 8, self.sys_clk_freq, spi_clk_freq)
+            spisdcard.add_clk_divider()
+            setattr(self.submodules, 'spisdcard', spisdcard)
+            self.add_csr('spisdcard')
 
         # EINTs - very simple, wire up top 3 bits to ls180 "eint" pins
         eintpads = self.cpu.cpupads['eint']
         print ("eintpads", eintpads)
-        self.comb += self.cpu.interrupt[12:16].eq(eintpads)
+        self.eint_tmp = Signal(len(eintpads))
+        for i in range(len(eintpads)):
+            self.comb += self.cpu.interrupt[13+i].eq(self.eint_tmp[i])
+            self.comb += self.eint_tmp[i].eq(getattr(eintpads, "%d" % i))
 
         # JTAG
         jtagpads = platform.request("jtag")
@@ -503,11 +549,12 @@ class LibreSoCSim(SoCCore):
             self.sync += self.dummy[i].eq(self.nc[i] | self.cpu.interrupt[0])
 
         # PWM
-        pwmpads = self.cpu.cpupads['pwm']
-        for i in range(2):
-            name = "pwm%d" % i
-            setattr(self.submodules, name, PWM(pwmpads[i]))
-            self.add_csr(name)
+        if hasattr(self.cpu.cpupads, 'pwm'):
+            pwmpads = self.cpu.cpupads['pwm']
+            for i in range(2):
+                name = "pwm%d" % i
+                setattr(self.submodules, name, PWM(pwmpads[i]))
+                self.add_csr(name)
 
         # I2C Master
         i2c_core_pads = self.cpu.cpupads['mtwi']
@@ -516,41 +563,42 @@ class LibreSoCSim(SoCCore):
 
         # SDCard -----------------------------------------------------
 
-        # Emulator / Pads
-        sdcard_pads = self.cpu.cpupads['sd0']
-
-        # 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")
+        if hasattr(self.cpu.cpupads, 'sd0'):
+            # Emulator / Pads
+            sdcard_pads = self.cpu.cpupads['sd0']
+
+            # 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:
             return
 
-        jtag_en = ('jtag' in variant) or variant == 'ls180'
+        jtag_en = ('jtag' in variant) or ('ls180' in variant)
 
         # setup running of DMI FSM
         dmi_addr = Signal(4)
@@ -828,13 +876,21 @@ def main():
                         help="Cycle to start FST tracing")
     parser.add_argument("--trace-end",    default=-1,
                         help="Cycle to end FST tracing")
+    parser.add_argument("--num-srams",    default=5,
+                        help="number of srams")
+    parser.add_argument("--srams4k",    action="store_true",
+                        help="enable 4k srams")
     parser.add_argument("--build", action="store_true", help="Build bitstream")
     args = parser.parse_args()
 
+    print ("number of SRAMs", args.num_srams)
+    print ("enable 4K SRAMs variant", args.srams4k)
 
-    if args.platform == 'ls180':
+    if 'ls180' in args.platform:
         soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
-                          platform=args.platform)
+                          platform=args.platform,
+                          srams_4k=args.srams4k,
+                          dff_srams=args.num_srams)
         builder = Builder(soc, compile_gateware = True)
         builder.build(run         = True)
         os.chdir("../")
@@ -845,7 +901,8 @@ def main():
 
         for i in range(2):
             soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
-                              platform=args.platform)
+                              platform=args.platform,
+                              dff_srams=args.num_srams)
             builder = Builder(soc, compile_gateware = i!=0)
             builder.build(sim_config=sim_config,
                 run         = i!=0,