argh got fed up trying to shoe-horn into sim.py
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 18 Sep 2020 21:35:12 +0000 (22:35 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 18 Sep 2020 21:35:12 +0000 (22:35 +0100)
src/soc/litex/florent/libresoc/ls180.py
src/soc/litex/florent/ls180soc.py [new file with mode: 0755]

index 4b37271a4441e541bc4c6ba0c6568af090dbd41d..b17cb8b42299ed7fb2cd995a88cce821ef8a18a7 100644 (file)
@@ -4,13 +4,16 @@
 # Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
 # SPDX-License-Identifier: BSD-2-Clause
 
-from litex.build.generic_platform import GenericPlatform
+from migen.fhdl.structure import _Fragment
+from litex.build.generic_platform import (GenericPlatform, Pins,
+                                        Subsignal, IOStandard, Misc,
+                                        )
 import os
 
 # IOs ----------------------------------------------------------------------------------------------
 
 _io = [
-    ("clk", 0, Pins("G2"), IOStandard("LVCMOS33")),
+    ("sys_clk", 0, Pins("G2"), IOStandard("LVCMOS33")),
     ("rst",   0, Pins("R1"), IOStandard("LVCMOS33")),
 
     ("serial", 0,
@@ -32,7 +35,7 @@ _io = [
         IOStandard("LVCMOS33"),
     ),
 
-    ("spi", 1,
+    ("spisdcard", 0,
         Subsignal("clk",  Pins("J1")),
         Subsignal("mosi", Pins("J3"), Misc("PULLMODE=UP")),
         Subsignal("cs_n", Pins("H1"), Misc("PULLMODE=UP")),
@@ -71,26 +74,28 @@ _io = [
 ]
 
 for i in range(8):
-    _io.append(( ("gpio_in", i, Pins("X%d" % i), IOStandard("LVCMOS33")) )
-    _io.append(( ("gpio_out", i, Pins("Y%d" % i), IOStandard("LVCMOS33")) )
+    _io.append( ("gpio_in", i, Pins("X%d" % i), IOStandard("LVCMOS33")) )
+    _io.append( ("gpio_out", i, Pins("Y%d" % i), IOStandard("LVCMOS33")) )
 
 # Platform -----------------------------------------------------------------------------------------
 
-class Platform(GenericPlatform):
-    default_clk_name   = "clk"
+class LS180Platform(GenericPlatform):
+    default_clk_name   = "sys_clk"
     default_clk_period = 1e9/50e6
 
     def __init__(self, device="LS180", **kwargs):
         assert device in ["LS180"]
         GenericPlatform.__init__(self, device, _io, **kwargs)
 
-    def build(self, platform, fragment,
+    def build(self, fragment,
                     build_dir      = "build",
                     build_name     = "top",
                     run            = True,
                     timingstrict   = True,
                     **kwargs):
 
+        platform = self
+
         # Create build directory
         os.makedirs(build_dir, exist_ok=True)
         cwd = os.getcwd()
@@ -114,5 +119,6 @@ class Platform(GenericPlatform):
 
     def do_finalize(self, fragment):
         super().do_finalize(fragment)
+        return
         self.add_period_constraint(self.lookup_request("clk", loose=True),
                                    1e9/50e6)
diff --git a/src/soc/litex/florent/ls180soc.py b/src/soc/litex/florent/ls180soc.py
new file mode 100755 (executable)
index 0000000..6220856
--- /dev/null
@@ -0,0 +1,499 @@
+#!/usr/bin/env python3
+
+import os
+import argparse
+
+from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState)
+
+from litex.build.generic_platform import Pins, Subsignal
+from litex.build.sim import SimPlatform
+from litex.build.io import CRG
+from litex.build.sim.config import SimConfig
+
+from litex.soc.integration.soc import SoCRegion
+from litex.soc.integration.soc_core import SoCCore
+from litex.soc.integration.soc_sdram import SoCSDRAM
+from litex.soc.integration.builder import Builder
+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.tools.litex_sim import sdram_module_nphases, get_sdram_phy_settings
+
+from litex.tools.litex_sim import Platform
+from libresoc.ls180 import LS180Platform
+
+from libresoc import LibreSoC
+from microwatt import Microwatt
+
+# HACK!
+from litex.soc.integration.soc import SoCCSRHandler
+SoCCSRHandler.supported_address_width.append(12)
+
+# LibreSoCSim -----------------------------------------------------------------
+
+class LibreSoCSim(SoCCore):
+    def __init__(self, cpu="libresoc", debug=False, with_sdram=True,
+            sdram_module          = "AS4C16M16",
+            #sdram_data_width      = 16,
+            #sdram_module          = "MT48LC16M16",
+            sdram_data_width      = 16,
+            irq_reserved_irqs = {'uart': 0},
+            platform='sim',
+            ):
+        assert cpu in ["libresoc", "microwatt"]
+        sys_clk_freq = int(100e6)
+
+        if platform == 'sim':
+            platform     = Platform()
+            uart_name = "sim"
+        elif platform == 'ls180':
+            platform     = LS180Platform()
+            uart_name = "serial"
+
+        #cpu_data_width = 32
+        cpu_data_width = 64
+
+        if cpu_data_width == 32:
+            variant = "standard32"
+        else:
+            variant = "standard"
+
+        #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+        #            "hello_world/hello_world.bin"
+        #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+        #            "tests/1.bin"
+        #ram_fname = "/tmp/test.bin"
+        #ram_fname = None
+        #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+        #            "micropython/firmware.bin"
+        #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+        #            "tests/xics/xics.bin"
+        ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+                    "tests/decrementer/decrementer.bin"
+        #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+        #            "hello_world/hello_world.bin"
+
+        # reserve XICS ICP and XICS memory addresses.
+        self.mem_map['icp'] = 0xc0004000
+        self.mem_map['ics'] = 0xc0005000
+        self.mem_map['gpio'] = 0xc0007000
+        #self.csr_map["icp"] = 8  #  8 x 0x800 == 0x4000
+        #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
+
+        ram_init = []
+        if ram_fname:
+            #ram_init = get_mem_data({
+            #    ram_fname:       "0x00000000",
+            #    }, "little")
+            ram_init = get_mem_data(ram_fname, "little")
+
+            # remap the main RAM to reset-start-address
+            self.mem_map["main_ram"] = 0x00000000
+
+            # without sram nothing works, therefore move it to higher up
+            self.mem_map["sram"] = 0x90000000
+
+            # put UART at 0xc000200 (w00t!  this works!)
+            self.csr_map["uart"] = 4
+
+
+        # SoCCore -------------------------------------------------------------
+        SoCCore.__init__(self, platform, clk_freq=sys_clk_freq,
+            cpu_type                 = "microwatt",
+            cpu_cls                  = LibreSoC   if cpu == "libresoc" \
+                                       else Microwatt,
+            #bus_data_width           = 64,
+            csr_address_width        = 12, # limit to 0x4000
+            cpu_variant              = variant,
+            csr_data_width            = 8,
+            l2_size             = 0,
+            uart_name                = uart_name,
+            with_sdram               = with_sdram,
+            sdram_module          = sdram_module,
+            sdram_data_width      = sdram_data_width,
+            integrated_rom_size      = 0 if ram_fname else 0x10000,
+            integrated_sram_size     = 0x40000,
+            #integrated_main_ram_init  = ram_init,
+            integrated_main_ram_size = 0x00000000 if with_sdram \
+                                        else 0x10000000 , # 256MB
+            )
+        self.platform.name = "sim"
+
+        # SDR SDRAM ----------------------------------------------
+        if False: # not self.integrated_main_ram_size:
+            self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"))
+
+
+        if cpu == "libresoc":
+            # XICS interrupt devices
+            icp_addr = self.mem_map['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_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)
+
+            # Simple GPIO peripheral
+            gpio_addr = self.mem_map['gpio']
+            gpio_wb = self.cpu.simple_gpio
+            gpio_region = SoCRegion(origin=gpio_addr, size=0x20, cached=False)
+            self.bus.add_slave(name='gpio', slave=gpio_wb, region=gpio_region)
+
+
+        # CRG -----------------------------------------------------------------
+        self.submodules.crg = CRG(platform.request("sys_clk"))
+
+        #ram_init = []
+
+        # SDRAM ----------------------------------------------------
+        if with_sdram:
+            sdram_clk_freq   = int(100e6) # FIXME: use 100MHz timings
+            sdram_module_cls = getattr(litedram_modules, sdram_module)
+            sdram_rate       = "1:{}".format(
+                    sdram_module_nphases[sdram_module_cls.memtype])
+            sdram_module     = sdram_module_cls(sdram_clk_freq, sdram_rate)
+            phy_settings     = get_sdram_phy_settings(
+                            memtype    = sdram_module.memtype,
+                            data_width = sdram_data_width,
+                            clk_freq   = sdram_clk_freq)
+            #sdrphy_cls = HalfRateGENSDRPHY 
+            sdrphy_cls = GENSDRPHY
+            self.submodules.sdrphy = sdrphy_cls(platform.request("sdram"))
+            #self.submodules.sdrphy = sdrphy_cls(sdram_module,
+            #                                       phy_settings,
+            #                                       init=ram_init
+            #                                        )
+            self.add_sdram("sdram",
+                phy                     = self.sdrphy,
+                module                  = sdram_module,
+                origin                  = self.mem_map["main_ram"],
+                size                    = 0x40000000,
+                l2_cache_size           = 0, # 8192
+                l2_cache_min_data_width = 128,
+                l2_cache_reverse        = True
+            )
+            # FIXME: skip memtest to avoid corrupting memory
+            self.add_constant("MEMTEST_BUS_SIZE",  128//16)
+            self.add_constant("MEMTEST_DATA_SIZE", 128//16)
+            self.add_constant("MEMTEST_ADDR_SIZE", 128//16)
+            self.add_constant("MEMTEST_BUS_DEBUG", 1)
+            self.add_constant("MEMTEST_ADDR_DEBUG", 1)
+            self.add_constant("MEMTEST_DATA_DEBUG", 1)
+
+
+        # Debug ---------------------------------------------------------------
+        if not debug:
+            return
+
+        # setup running of DMI FSM
+        dmi_addr = Signal(4)
+        dmi_din = Signal(64)
+        dmi_dout = Signal(64)
+        dmi_wen = Signal(1)
+        dmi_req = Signal(1)
+
+        # debug log out
+        dbg_addr = Signal(4)
+        dbg_dout = Signal(64)
+        dbg_msg = Signal(1)
+
+        # capture pc from dmi
+        pc = Signal(64)
+        active_dbg = Signal()
+        active_dbg_cr = Signal()
+        active_dbg_xer = Signal()
+
+        # xer flags
+        xer_so = Signal()
+        xer_ca = Signal()
+        xer_ca32 = Signal()
+        xer_ov = Signal()
+        xer_ov32 = Signal()
+
+        # increment counter, Stop after 100000 cycles
+        uptime = Signal(64)
+        self.sync += uptime.eq(uptime + 1)
+        #self.sync += If(uptime == 1000000000000, Finish())
+
+        # DMI FSM counter and FSM itself
+        dmicount = Signal(10)
+        dmirunning = Signal(1)
+        dmi_monitor = Signal(1)
+        dmifsm = FSM()
+        self.submodules += dmifsm
+
+        # DMI FSM
+        dmifsm.act("START",
+            If(dmi_req & dmi_wen,
+                (self.cpu.dmi_addr.eq(dmi_addr),   # DMI Addr
+                 self.cpu.dmi_din.eq(dmi_din), # DMI in
+                 self.cpu.dmi_req.eq(1),    # DMI request
+                 self.cpu.dmi_wr.eq(1),    # DMI write
+                 If(self.cpu.dmi_ack,
+                    (NextState("IDLE"),
+                    )
+                 ),
+                ),
+            ),
+            If(dmi_req & ~dmi_wen,
+                (self.cpu.dmi_addr.eq(dmi_addr),   # DMI Addr
+                 self.cpu.dmi_req.eq(1),    # DMI request
+                 self.cpu.dmi_wr.eq(0),    # DMI read
+                 If(self.cpu.dmi_ack,
+                    # acknowledge received: capture data.
+                    (NextState("IDLE"),
+                     NextValue(dbg_addr, dmi_addr),
+                     NextValue(dbg_dout, self.cpu.dmi_dout),
+                     NextValue(dbg_msg, 1),
+                    ),
+                 ),
+                ),
+            )
+        )
+
+        # DMI response received: reset the dmi request and check if
+        # in "monitor" mode
+        dmifsm.act("IDLE",
+            If(dmi_monitor,
+                 NextState("FIRE_MONITOR"), # fire "monitor" on next cycle
+            ).Else(
+                 NextState("START"), # back to start on next cycle
+            ),
+            NextValue(dmi_req, 0),
+            NextValue(dmi_addr, 0),
+            NextValue(dmi_din, 0),
+            NextValue(dmi_wen, 0),
+        )
+
+        # "monitor" mode fires off a STAT request
+        dmifsm.act("FIRE_MONITOR",
+            (NextValue(dmi_req, 1),
+             NextValue(dmi_addr, 1), # DMI STAT address
+             NextValue(dmi_din, 0),
+             NextValue(dmi_wen, 0), # read STAT
+             NextState("START"), # back to start on next cycle
+            )
+        )
+
+        self.comb += xer_so.eq((dbg_dout & 1) == 1)
+        self.comb += xer_ca.eq((dbg_dout & 4) == 4)
+        self.comb += xer_ca32.eq((dbg_dout & 8) == 8)
+        self.comb += xer_ov.eq((dbg_dout & 16) == 16)
+        self.comb += xer_ov32.eq((dbg_dout & 32) == 32)
+
+        # debug messages out
+        self.sync += If(dbg_msg,
+            (If(active_dbg & (dbg_addr == 0b10), # PC
+                Display("pc : %016x", dbg_dout),
+             ),
+             If(dbg_addr == 0b10, # PC
+                 pc.eq(dbg_dout),     # capture PC
+             ),
+             #If(dbg_addr == 0b11, # MSR
+             #   Display("    msr: %016x", dbg_dout),
+             #),
+             If(dbg_addr == 0b1000, # CR
+                Display("    cr : %016x", dbg_dout),
+             ),
+             If(dbg_addr == 0b1001, # XER
+                Display("    xer: so %d ca %d 32 %d ov %d 32 %d",
+                            xer_so, xer_ca, xer_ca32, xer_ov, xer_ov32),
+             ),
+             If(dbg_addr == 0b101, # GPR
+                Display("    gpr: %016x", dbg_dout),
+             ),
+            # also check if this is a "stat"
+            If(dbg_addr == 1, # requested a STAT
+                #Display("    stat: %x", dbg_dout),
+                If(dbg_dout & 2, # bit 2 of STAT is "stopped" mode
+                     dmirunning.eq(1), # continue running
+                     dmi_monitor.eq(0), # and stop monitor mode
+                ),
+            ),
+             dbg_msg.eq(0)
+            )
+        )
+
+        # kick off a "stop"
+        self.sync += If(uptime == 0,
+            (dmi_addr.eq(0), # CTRL
+             dmi_din.eq(1<<0), # STOP
+             dmi_req.eq(1),
+             dmi_wen.eq(1),
+            )
+        )
+
+        self.sync += If(uptime == 4,
+             dmirunning.eq(1),
+        )
+
+        self.sync += If(dmirunning,
+             dmicount.eq(dmicount + 1),
+        )
+
+        # loop every 1<<N cycles
+        cyclewid = 9
+
+        # get the PC
+        self.sync += If(dmicount == 4,
+            (dmi_addr.eq(0b10), # NIA
+             dmi_req.eq(1),
+             dmi_wen.eq(0),
+            )
+        )
+
+        # kick off a "step"
+        self.sync += If(dmicount == 8,
+            (dmi_addr.eq(0), # CTRL
+             dmi_din.eq(1<<3), # STEP
+             dmi_req.eq(1),
+             dmi_wen.eq(1),
+             dmirunning.eq(0), # stop counter, need to fire "monitor"
+             dmi_monitor.eq(1), # start "monitor" instead
+            )
+        )
+
+        # limit range of pc for debug reporting
+        #self.comb += active_dbg.eq((0x378c <= pc) & (pc <= 0x38d8))
+        #self.comb += active_dbg.eq((0x0 < pc) & (pc < 0x58))
+        self.comb += active_dbg.eq(1)
+
+
+        # get the MSR
+        self.sync += If(active_dbg & (dmicount == 12),
+            (dmi_addr.eq(0b11), # MSR
+             dmi_req.eq(1),
+             dmi_wen.eq(0),
+            )
+        )
+
+        if cpu == "libresoc":
+            #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
+            self.comb += active_dbg_cr.eq(0)
+
+            # get the CR
+            self.sync += If(active_dbg_cr & (dmicount == 16),
+                (dmi_addr.eq(0b1000), # CR
+                 dmi_req.eq(1),
+                 dmi_wen.eq(0),
+                )
+            )
+
+            #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
+            self.comb += active_dbg_xer.eq(active_dbg_cr)
+
+            # get the CR
+            self.sync += If(active_dbg_xer & (dmicount == 20),
+                (dmi_addr.eq(0b1001), # XER
+                 dmi_req.eq(1),
+                 dmi_wen.eq(0),
+                )
+            )
+
+        # read all 32 GPRs
+        for i in range(32):
+            self.sync += If(active_dbg & (dmicount == 24+(i*8)),
+                (dmi_addr.eq(0b100), # GSPR addr
+                 dmi_din.eq(i), # r1
+                 dmi_req.eq(1),
+                 dmi_wen.eq(1),
+                )
+            )
+
+            self.sync += If(active_dbg & (dmicount == 28+(i*8)),
+                (dmi_addr.eq(0b101), # GSPR data
+                 dmi_req.eq(1),
+                 dmi_wen.eq(0),
+                )
+            )
+
+        # monitor bbus read/write
+        self.sync += If(active_dbg & self.cpu.dbus.stb & self.cpu.dbus.ack,
+            Display("    [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
+                #uptime,
+                0,
+                self.cpu.dbus.adr,
+                self.cpu.dbus.we,
+                self.cpu.dbus.sel,
+                self.cpu.dbus.dat_w,
+                self.cpu.dbus.dat_r
+            )
+        )
+
+        return
+
+        # monitor ibus write
+        self.sync += If(active_dbg & self.cpu.ibus.stb & self.cpu.ibus.ack &
+                        self.cpu.ibus.we,
+            Display("    [%06x] iadr: %8x, s %01x w %016x",
+                #uptime,
+                0,
+                self.cpu.ibus.adr,
+                self.cpu.ibus.sel,
+                self.cpu.ibus.dat_w,
+            )
+        )
+        # monitor ibus read
+        self.sync += If(active_dbg & self.cpu.ibus.stb & self.cpu.ibus.ack &
+                        ~self.cpu.ibus.we,
+            Display("    [%06x] iadr: %8x, s %01x r %016x",
+                #uptime,
+                0,
+                self.cpu.ibus.adr,
+                self.cpu.ibus.sel,
+                self.cpu.ibus.dat_r
+            )
+        )
+
+# Build -----------------------------------------------------------------------
+
+def main():
+    parser = argparse.ArgumentParser(description="LiteX LibreSoC CPU Sim")
+    parser.add_argument("--cpu",          default="libresoc",
+                        help="CPU to use: libresoc (default) or microwatt")
+    parser.add_argument("--platform",     default="sim",
+                        help="platform (sim or ls180)")
+    parser.add_argument("--debug",        action="store_true",
+                        help="Enable debug traces")
+    parser.add_argument("--trace",        action="store_true",
+                        help="Enable tracing")
+    parser.add_argument("--trace-start",  default=0,
+                        help="Cycle to start FST tracing")
+    parser.add_argument("--trace-end",    default=-1,
+                        help="Cycle to end FST tracing")
+    parser.add_argument("--build", action="store_true", help="Build bitstream")
+    args = parser.parse_args()
+
+
+    if args.platform == 'ls180':
+        soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
+                          platform=args.platform)
+        #soc.add_sdcard()
+        builder = Builder(soc, compile_gateware = True)
+        builder.build(run         = True)
+        os.chdir("../")
+    else:
+
+        sim_config = SimConfig(default_clk="sys_clk")
+        sim_config.add_module("serial2console", "serial")
+
+        for i in range(2):
+            soc = LibreSoCSim(cpu=args.cpu, debug=args.debug,
+                              platform=args.platform)
+            builder = Builder(soc, compile_gateware = i!=0)
+            builder.build(sim_config=sim_config,
+                run         = i!=0,
+                trace       = args.trace,
+                trace_start = int(args.trace_start),
+                trace_end   = int(args.trace_end),
+                trace_fst   = 0)
+            os.chdir("../")
+
+if __name__ == "__main__":
+    main()