create new function teststate_check_regs which is called by check_regs
[soc.git] / src / soc / debug / jtag.py
index b1091dac28e31765bdf028191e68bb791894cbed..4b4f17a97d672c3f22b668008a1c058ac2500da6 100644 (file)
@@ -3,7 +3,8 @@
 using Staf Verhaegen (Chips4Makers) wishbone TAP
 """
 
 using Staf Verhaegen (Chips4Makers) wishbone TAP
 """
 
-from nmigen import (Module, Signal, Elaboratable)
+from collections import OrderedDict
+from nmigen import (Module, Signal, Elaboratable, Cat)
 from nmigen.cli import rtlil
 from c4m.nmigen.jtag.tap import IOType
 from soc.debug.dmi import  DMIInterface, DBGCore
 from nmigen.cli import rtlil
 from c4m.nmigen.jtag.tap import IOType
 from soc.debug.dmi import  DMIInterface, DBGCore
@@ -12,72 +13,129 @@ from soc.debug.dmi2jtag import DMITAP
 # map from pinmux to c4m jtag iotypes
 iotypes = {'-': IOType.In,
            '+': IOType.Out,
 # map from pinmux to c4m jtag iotypes
 iotypes = {'-': IOType.In,
            '+': IOType.Out,
-           '*': IOType.InTriOut}
+           '>': IOType.TriOut,
+           '*': IOType.InTriOut,
+        }
+
+scanlens = {IOType.In: 1,
+           IOType.Out: 1,
+           IOType.TriOut: 2,
+           IOType.InTriOut: 3,
+            }
+
+def dummy_pinset():
+    # sigh this needs to come from pinmux.
+    gpios = []
+    for i in range(16):
+        gpios.append("%d*" % i)
+    return {'uart': ['tx+', 'rx-'],
+             'gpio': gpios,
+             'i2c': ['sda*', 'scl+']}
 
 # TODO: move to suitable location
 class Pins:
 
 # TODO: move to suitable location
 class Pins:
-
-    def __init__(self):
-
-        # sigh this needs to come from pinmux.
-        gpios = []
-        for i in range(16):
-            gpios.append("gpio%d*" % i)
-        self.io_names = {'serial': ['tx+', 'rx-'], 'gpio': gpios}
+    """declare a list of pins, including name and direction.  grouped by fn
+    the pin dictionary needs to be in a reliable order so that the JTAG
+    Boundary Scan is also in a reliable order
+    """
+    def __init__(self, pindict):
+        self.io_names = OrderedDict()
+        if isinstance(pindict, OrderedDict):
+            self.io_names.update(pindict)
+        else:
+            keys = list(pindict.keys())
+            keys.sort()
+            for k in keys:
+                self.io_names[k] = pindict[k]
 
     def __iter__(self):
 
     def __iter__(self):
-        # start parsing io_names and create IOConn Records
+        # start parsing io_names and enumerate them to return pin specs
+        scan_idx = 0
         for fn, pins in self.io_names.items():
             for pin in pins:
                 # decode the pin name and determine the c4m jtag io type
                 name, pin_type = pin[:-1], pin[-1]
                 iotype = iotypes[pin_type]
                 pin_name = "%s_%s" % (fn, name)
         for fn, pins in self.io_names.items():
             for pin in pins:
                 # decode the pin name and determine the c4m jtag io type
                 name, pin_type = pin[:-1], pin[-1]
                 iotype = iotypes[pin_type]
                 pin_name = "%s_%s" % (fn, name)
-                yield (fn, name, iotype, pin_name)
+                yield (fn, name, iotype, pin_name, scan_idx)
+                scan_idx += scanlens[iotype] # inc boundary reg scan offset
+
 
 class JTAG(DMITAP, Pins):
 
 class JTAG(DMITAP, Pins):
-    def __init__(self):
+    # 32-bit data width here so that it matches with litex
+    def __init__(self, pinset, domain, wb_data_wid=32):
+        self.domain = domain
         DMITAP.__init__(self, ir_width=4)
         DMITAP.__init__(self, ir_width=4)
-        Pins.__init__(self)
-
-        # sigh this needs to come from pinmux.
-        gpios = []
-        for i in range(16):
-            gpios.append("gpio%d*" % i)
-        self.io_names = {'serial': ['tx+', 'rx-'], 'gpio': gpios}
-
-        # start parsing io_names and create IOConn Records
-        self.ios = []
-        for fn, pin, iotype, pin_name in list(self):
-            self.ios.append(self.add_io(iotype=iotype, name=pin_name))
+        Pins.__init__(self, pinset)
+
+        # enumerate pin specs and create IOConn Records.
+        # we store the boundary scan register offset in the IOConn record
+        self.ios = [] # these are enumerated in external_ports
+        self.scan_len = 0
+        for fn, pin, iotype, pin_name, scan_idx in list(self):
+            io = self.add_io(iotype=iotype, name=pin_name)
+            io._scan_idx = scan_idx # hmm shouldn't really do this
+            self.scan_len += scan_idx # record full length of boundary scan
+            self.ios.append(io)
 
         # this is redundant.  or maybe part of testing, i don't know.
 
         # this is redundant.  or maybe part of testing, i don't know.
-        self.sr = self.add_shiftreg(ircode=4, length=3)
+        self.sr = self.add_shiftreg(ircode=4, length=3,
+                                    domain=domain)
 
 
-        # create and connect wishbone 
-        self.wb = self.add_wishbone(ircodes=[5, 6, 7],
-                                   address_width=29, data_width=64,
-                                   name="jtag_wb")
+        # create and connect wishbone
+        self.wb = self.add_wishbone(ircodes=[5, 6, 7], features={'err'},
+                                   address_width=30, data_width=wb_data_wid,
+                                   granularity=8, # 8-bit wide
+                                   name="jtag_wb",
+                                   domain=domain)
 
         # create DMI2JTAG (goes through to dmi_sim())
 
         # create DMI2JTAG (goes through to dmi_sim())
-        self.dmi = self.add_dmi(ircodes=[8, 9, 10])
+        self.dmi = self.add_dmi(ircodes=[8, 9, 10],
+                                    domain=domain)
+
+        # use this for enable/disable of parts of the ASIC.
+        # XXX make sure to add the _en sig to en_sigs list
+        self.wb_icache_en = Signal(reset=1)
+        self.wb_dcache_en = Signal(reset=1)
+        self.wb_sram_en = Signal(reset=1)
+        self.en_sigs = en_sigs = Cat(self.wb_icache_en, self.wb_dcache_en,
+                                     self.wb_sram_en)
+        self.sr_en = self.add_shiftreg(ircode=11, length=len(en_sigs),
+                                       domain=domain)
 
     def elaborate(self, platform):
         m = super().elaborate(platform)
         m.d.comb += self.sr.i.eq(self.sr.o) # loopback as part of test?
 
     def elaborate(self, platform):
         m = super().elaborate(platform)
         m.d.comb += self.sr.i.eq(self.sr.o) # loopback as part of test?
+
+        # provide way to enable/disable wishbone caches and SRAM
+        # just in case of issues
+        # see https://bugs.libre-soc.org/show_bug.cgi?id=520
+        with m.If(self.sr_en.oe):
+            m.d.sync += self.en_sigs.eq(self.sr_en.o)
+        # also make it possible to read the enable/disable current state
+        with m.If(self.sr_en.ie):
+            m.d.comb += self.sr_en.i.eq(self.en_sigs)
+
+        # create a fake "stall"
+        #wb = self.wb
+        #m.d.comb += wb.stall.eq(wb.cyc & ~wb.ack) # No burst support
+
         return m
 
     def external_ports(self):
         return m
 
     def external_ports(self):
-        ports = super().external_ports()
-        ports += list(self.wb.fields.values())
+        """create a list of ports that goes into the top level il (or verilog)
+        """
+        ports = super().external_ports()           # gets JTAG signal names
+        ports += list(self.wb.fields.values())     # wishbone signals
         for io in self.ios:
         for io in self.ios:
-            ports += list(io.core.fields.values())
-            ports += list(io.pad.fields.values())
+            ports += list(io.core.fields.values()) # io "core" signals
+            ports += list(io.pad.fields.values())  # io "pad" signals"
         return ports
 
 
 if __name__ == '__main__':
         return ports
 
 
 if __name__ == '__main__':
-    dut = JTAG()
+    pinset = dummy_pinset()
+    dut = JTAG(pinset)
 
     vl = rtlil.convert(dut)
     with open("test_jtag.il", "w") as f:
 
     vl = rtlil.convert(dut)
     with open("test_jtag.il", "w") as f: