add verilog build option, make DDR3 PHY optional, add UART pins
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 14 Feb 2022 10:34:48 +0000 (10:34 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 14 Feb 2022 10:34:48 +0000 (10:34 +0000)
src/ls2.py

index 362dfa576bf810efb15585bdd991d53325337fb9..c39ca5d3156602891a6f83e81d79e9160068fc54 100644 (file)
@@ -7,7 +7,8 @@
 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
 # under EU Grants 871528 and 957073, under the LGPLv3+ License
 
-from nmigen import (Module, Elaboratable, DomainRenamer)
+from nmigen import (Module, Elaboratable, DomainRenamer, Record)
+from nmigen.cli import verilog
 from nmigen.lib.cdc import ResetSynchronizer
 from nmigen_soc import wishbone, memory
 from nmigen_soc.memory import MemoryMap
@@ -82,31 +83,32 @@ class DDR3SoC(SoC, Elaboratable):
         self._decoder.add(self.ram.bus, addr=0x8000000) # SRAM at 0x8000_000
 
         # UART
-        self.uart = UART16550()
-        umap = MemoryMap(addr_width=7, data_width=8, name="uart_map")
-        #umap.add_resource(self._mem, name="mem", size=1<<5)
-        self.uart.bus.memory_map = umap
-
-        self._decoder.add(self.uart.bus, addr=0xc0002000) # 16550 UART address
+        if uart_pins is not None:
+            self.uart = UART16550()
+            umap = MemoryMap(addr_width=7, data_width=8, name="uart_map")
+            #umap.add_resource(self._mem, name="mem", size=1<<5)
+            self.uart.bus.memory_map = umap
+            self._decoder.add(self.uart.bus, addr=0xc0002000) # 16550 UART addr
 
         # DRAM Module
-        self.ddrphy = DomainRenamer("dramsync")(ECP5DDRPHY(ddr_pins,
-                                                sys_clk_freq=100e6))
-        self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
+        if ddr_pins is not None:
+            self.ddrphy = DomainRenamer("dramsync")(ECP5DDRPHY(ddr_pins,
+                                                    sys_clk_freq=100e6))
+            self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
 
-        ddrmodule = MT41K256M16(clk_freq, "1:2") # match DDR3 ASIC P/N
+            ddrmodule = MT41K256M16(clk_freq, "1:2") # match DDR3 ASIC P/N
 
-        drs = DomainRenamer("dramsync")
-        dramcore = gramCore(phy=self.ddrphy,
-                            geom_settings=ddrmodule.geom_settings,
-                            timing_settings=ddrmodule.timing_settings,
-                            clk_freq=clk_freq)
-        self.dramcore = drs(dramcore)
-        self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
+            drs = DomainRenamer("dramsync")
+            dramcore = gramCore(phy=self.ddrphy,
+                                geom_settings=ddrmodule.geom_settings,
+                                timing_settings=ddrmodule.timing_settings,
+                                clk_freq=clk_freq)
+            self.dramcore = drs(dramcore)
+            self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
 
-        # map the DRAM onto Wishbone
-        self.drambone = drs(gramWishbone(self.dramcore))
-        self._decoder.add(self.drambone.bus, addr=ddr_addr)
+            # map the DRAM onto Wishbone
+            self.drambone = drs(gramWishbone(self.dramcore))
+            self._decoder.add(self.drambone.bus, addr=ddr_addr)
 
         self.memory_map = self._decoder.bus.memory_map
 
@@ -117,7 +119,8 @@ class DDR3SoC(SoC, Elaboratable):
         comb = m.d.comb
 
         # add the peripherals and clock-reset-generator
-        m.submodules.sysclk = self.crg
+        if platform is not None:
+            m.submodules.sysclk = self.crg
 
         if hasattr(self, "rom"):
             m.submodules.rom = self.rom
@@ -128,12 +131,14 @@ class DDR3SoC(SoC, Elaboratable):
             m.submodules.cpu = self.cpu
         m.submodules.arbiter = self._arbiter
         m.submodules.decoder = self._decoder
-        m.submodules.ddrphy = self.ddrphy
-        m.submodules.dramcore = self.dramcore
-        m.submodules.drambone = self.drambone
+        if hasattr(self, "ddrphy"):
+            m.submodules.ddrphy = self.ddrphy
+            m.submodules.dramcore = self.dramcore
+            m.submodules.drambone = self.drambone
 
         # add blinky lights so we know FPGA is alive
-        m.submodules.blinky = Blinky()
+        if platform is not None:
+            m.submodules.blinky = Blinky()
 
         # connect the arbiter (of wishbone masters)
         # to the decoder (addressing wishbone slaves)
@@ -146,15 +151,22 @@ class DDR3SoC(SoC, Elaboratable):
         # add uart16550 verilog source. assumes a directory
         # structure where ls2 has been checked out in a common
         # subdirectory as https://github.com/freecores/uart16550
-        opencores_16550 = "../../uart16550/rtl/verilog"
-        pth = os.path.split(__file__)[0]
-        pth = os.path.join(pth, opencores_16550)
-        fname = os.path.abspath(pth)
-        print (fname)
-        self.uart.add_verilog_source(fname, platform)
+        if platform is not None:
+            opencores_16550 = "../../uart16550/rtl/verilog"
+            pth = os.path.split(__file__)[0]
+            pth = os.path.join(pth, opencores_16550)
+            fname = os.path.abspath(pth)
+            print (fname)
+            self.uart.add_verilog_source(fname, platform)
 
         return m
 
+    def ports(self):
+        # puzzlingly the only IO ports needed are peripheral pins,
+        # and at the moment that's just UART tx/rx.
+        ports = []
+        ports += [self.uart.tx_o, self.uart.rx_i]
+        return ports
 
 if __name__ == "__main__":
 
@@ -175,6 +187,8 @@ if __name__ == "__main__":
                 }.get(fpga, None)
     if platform_kls is not None:
         platform = platform_kls(toolchain=toolchain)
+    else:
+        platform = None
 
     # select a firmware file
     firmware = None
@@ -190,6 +204,9 @@ if __name__ == "__main__":
                                     xdr={"clk":4, "a":4, "ba":4, "clk_en":4,
                                          "odt":4, "ras":4, "cas":4, "we":4})
         uart_pins = platform.request("uart", 0)
+    else:
+        ddr_pins = None
+        uart_pins = Record([('tx', 1), ('rx', 1)], name="uart_0")
 
     # set up the SOC
     soc = DDR3SoC(ddrphy_addr=0xff000000, # DRAM firmware init base
@@ -200,5 +217,12 @@ if __name__ == "__main__":
                   uart_pins=uart_pins,
                   firmware=firmware)
 
-    # build and upload it
-    platform.build(soc, do_program=True)
+    if platform is not None:
+        # build and upload it
+        platform.build(soc, do_program=True)
+    else:
+        # for now, generate verilog
+        vl = verilog.convert(soc, ports=soc.ports())
+        with open("test_ls2.v", "w") as f:
+            f.write(vl)
+