update README
[libresoc-litex.git] / sim.py
diff --git a/sim.py b/sim.py
index d3687aa4515fa6ecaee22d406e59e50ac0f3bfba..f4ec8dce544e5ede1ec909d86cd28a7b3d2df08b 100755 (executable)
--- a/sim.py
+++ b/sim.py
@@ -1,9 +1,17 @@
 #!/usr/bin/env python3
 
+# Notes for "Debug" mode:
+# both microwatt and Libre-SOC implement (pretty much) the same DMI
+# interface.  TBD: really, there should be an OPF Debug SIG which
+# defines this properly. still, these two are interoperable.
+# https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/debug/dmi.py
+# https://github.com/antonblanchard/microwatt/blob/master/core_debug.vhdl
+
 import os
 import argparse
 
 from migen import (Signal, FSM, If, Display, Finish, NextValue, NextState)
+from migen import Display as D
 
 from litex.build.generic_platform import Pins, Subsignal
 from litex.build.sim import SimPlatform
@@ -51,20 +59,22 @@ class LibreSoCSim(SoCSDRAM):
         #ram_fname = "/tmp/test.bin"
         #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/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"
-        ram_fname = None
+        ram_fname = "/home/lkcl/src/libresoc/microwatt/" \
+                    "tests/mmu/mmu.bin"
+        #ram_fname = None
 
         # reserve XICS ICP and XICS memory addresses.
-        self.mem_map['icp'] = 0xc0004000
-        self.mem_map['ics'] = 0xc0005000
+        self.mem_map['xicsicp'] = 0xc0004000
+        self.mem_map['xicsics'] = 0xc0005000
         self.mem_map['gpio'] = 0xc0007000
-        #self.csr_map["icp"] = 8  #  8 x 0x800 == 0x4000
-        #self.csr_map["ics"] = 10 # 10 x 0x800 == 0x5000
+        #self.csr_map["xicsicp"] = 8  #  8 x 0x800 == 0x4000
+        #self.csr_map["xicsics"] = 10 # 10 x 0x800 == 0x5000
 
         ram_init = []
         if ram_fname:
@@ -107,15 +117,15 @@ class LibreSoCSim(SoCSDRAM):
 
         if cpu == "libresoc":
             # XICS interrupt devices
-            icp_addr = self.mem_map['icp']
+            icp_addr = self.mem_map['xicsicp']
             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)
+            self.bus.add_slave(name='xicsicp', slave=icp_wb, region=icp_region)
 
-            ics_addr = self.mem_map['ics']
+            ics_addr = self.mem_map['xicsics']
             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)
+            self.bus.add_slave(name='xicsics', slave=ics_wb, region=ics_region)
 
         if "gpio" in variant:
             # Simple GPIO peripheral
@@ -158,27 +168,39 @@ class LibreSoCSim(SoCSDRAM):
             self.add_constant("MEMTEST_DATA_DEBUG", 1)
 
 
-        # add JTAG platform pins
-        platform.add_extension([
-            ("jtag", 0,
-                Subsignal("tck",  Pins(1)),
-                Subsignal("tms", Pins(1)),
-                Subsignal("tdi", Pins(1)),
-                Subsignal("tdo", Pins(1)),
-            )
-        ])
+        if "jtag" in variant:
+            # add JTAG platform pins
+            platform.add_extension([
+                ("jtag", 0,
+                    Subsignal("tck",  Pins(1)),
+                    Subsignal("tms", Pins(1)),
+                    Subsignal("tdi", Pins(1)),
+                    Subsignal("tdo", Pins(1)),
+                )
+            ])
 
-        jtagpads = platform.request("jtag")
-        self.comb += self.cpu.jtag_tck.eq(jtagpads.tck)
-        self.comb += self.cpu.jtag_tms.eq(jtagpads.tms)
-        self.comb += self.cpu.jtag_tdi.eq(jtagpads.tdi)
-        self.comb += jtagpads.tdo.eq(self.cpu.jtag_tdo)
+            jtagpads = platform.request("jtag")
+            self.comb += self.cpu.jtag_tck.eq(jtagpads.tck)
+            self.comb += self.cpu.jtag_tms.eq(jtagpads.tms)
+            self.comb += self.cpu.jtag_tdi.eq(jtagpads.tdi)
+            self.comb += jtagpads.tdo.eq(self.cpu.jtag_tdo)
 
 
         # Debug ---------------------------------------------------------------
+        # (enable with ./sim.py --debug --variant=standard)
         if not debug:
             return
 
+        # In debug mode, the DMI interface is used to perform single-step
+        # and dump of the full register set (MSR, r0-r31, CR, XER, PC).
+        # by running the exact same program with microwatt and libre-soc
+        # a straight "diff -u" of the complete progress dumps can be done
+        # and therefore computation instruction discrepancies found immediately
+        # and easily, running at "verilator" speed.
+        #
+        # the FSM is a bit of a dog's dinner, it relies on the way that DMI
+        # works, sending requests at periodic intervals. needs work. DoesTheJob.
+
         # setup running of DMI FSM
         dmi_addr = Signal(4)
         dmi_din = Signal(64)
@@ -188,6 +210,7 @@ class LibreSoCSim(SoCSDRAM):
 
         # debug log out
         dbg_addr = Signal(4)
+        regnum = Signal(6)
         dbg_dout = Signal(64)
         dbg_msg = Signal(1)
 
@@ -278,27 +301,43 @@ class LibreSoCSim(SoCSDRAM):
         # debug messages out
         self.sync += If(dbg_msg,
             (If(active_dbg & (dbg_addr == 0b10), # PC
-                Display("pc : %016x", dbg_dout),
+                D("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 == 0b11, # MSR
+                D("    msr: %016x", dbg_dout),
+             ),
              If(dbg_addr == 0b1000, # CR
-                Display("    cr : %016x", dbg_dout),
+                D("    cr : %016x", dbg_dout),
              ),
              If(dbg_addr == 0b1001, # XER
-                Display("    xer: so %d ca %d 32 %d ov %d 32 %d",
+                D("    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),
+             If(dbg_addr == 0b101, # GPRs (and "fast" SPRs)
+                If(regnum <= 31, D("  gpr%02x: %016x",
+                                         regnum, dbg_dout),), # GPRs
+                If(regnum == 32, D("     LR: %016x", dbg_dout),), # LR
+                If(regnum == 33, D("    CTR: %016x", dbg_dout),), # CTR
+                If(regnum == 34, D("   SRR0: %016x", dbg_dout),), # SRR0
+                If(regnum == 35, D("   SRR1: %016x", dbg_dout),), # SRR1
+                If(regnum == 36, D("  HSRR0: %016x", dbg_dout),), # HSRR0
+                If(regnum == 37, D("  HSRR1: %016x", dbg_dout),), # HSRR1
+                If(regnum == 38, D("  SPRG0: %016x", dbg_dout),), # SPRG0
+                If(regnum == 39, D("  SPRG1: %016x", dbg_dout),), # SPRG1
+                If(regnum == 40, D("  SPRG2: %016x", dbg_dout),), # SPRG2
+                If(regnum == 41, D("  SPRG3: %016x", dbg_dout),), # SPRG3
+                If(regnum == 42, D(" HSPRG0: %016x", dbg_dout),), # HSPRG0
+                If(regnum == 43, D(" HSPRG1: %016x", dbg_dout),), # HSPRG1
+                If(regnum == 44, D("    XER: %016x", dbg_dout),), # XER
+                If(regnum == 45, D("    TAR: %016x", dbg_dout),), # TAR
+                #If(regnum == 46, D(" SVSRR0: %016x", dbg_dout),), # SVSRR0
              ),
             # also check if this is a "stat"
             If(dbg_addr == 1, # requested a STAT
-                #Display("    stat: %x", dbg_dout),
+                #D("    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
@@ -352,7 +391,6 @@ class LibreSoCSim(SoCSDRAM):
         #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
@@ -361,7 +399,7 @@ class LibreSoCSim(SoCSDRAM):
             )
         )
 
-        if cpu == "libresoc":
+        if cpu == "libresoc": # XXX TODO: waiting on microwatt upstream patch
             #self.comb += active_dbg_cr.eq((0x10300 <= pc) & (pc <= 0x12600))
             self.comb += active_dbg_cr.eq(0)
 
@@ -376,7 +414,7 @@ class LibreSoCSim(SoCSDRAM):
             #self.comb += active_dbg_xer.eq((0x10300 <= pc) & (pc <= 0x1094c))
             self.comb += active_dbg_xer.eq(active_dbg_cr)
 
-            # get the CR
+            # get the XER
             self.sync += If(active_dbg_xer & (dmicount == 20),
                 (dmi_addr.eq(0b1001), # XER
                  dmi_req.eq(1),
@@ -384,11 +422,13 @@ class LibreSoCSim(SoCSDRAM):
                 )
             )
 
-        # read all 32 GPRs
-        for i in range(32):
+        # read all 32 GPRs plus the next 16 which in microwatt are
+        # the "fast" SPRs, LR, CTR, SRR0, SRR1, etc.
+        for i in range(48):
             self.sync += If(active_dbg & (dmicount == 24+(i*8)),
                 (dmi_addr.eq(0b100), # GSPR addr
-                 dmi_din.eq(i), # r1
+                 dmi_din.eq(i), # register number (0-31 GPR, 32-48 fast SPRs)
+                 regnum.eq(i),
                  dmi_req.eq(1),
                  dmi_wen.eq(1),
                 )
@@ -403,7 +443,7 @@ class LibreSoCSim(SoCSDRAM):
 
         # 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",
+            D("    [%06x] dadr: %8x, we %d s %01x w %016x r: %016x",
                 #uptime,
                 0,
                 self.cpu.dbus.adr,
@@ -419,7 +459,7 @@ class LibreSoCSim(SoCSDRAM):
         # 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",
+            D("    [%06x] iadr: %8x, s %01x w %016x",
                 #uptime,
                 0,
                 self.cpu.ibus.adr,
@@ -430,7 +470,7 @@ class LibreSoCSim(SoCSDRAM):
         # 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",
+            D("    [%06x] iadr: %8x, s %01x r %016x",
                 #uptime,
                 0,
                 self.cpu.ibus.adr,