code-cleanup / comments on JTAG IO
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 9 Oct 2020 13:12:02 +0000 (14:12 +0100)
committerStaf Verhaegen <staf@stafverhaegen.be>
Wed, 21 Apr 2021 17:43:58 +0000 (19:43 +0200)
c4m/nmigen/jtag/tap.py

index 4ead48c2621226e8c29cf02e394867670848f21e..e3de5c30068b4b064ba25387ca5837b47c79f0ae 100755 (executable)
@@ -158,6 +158,13 @@ class IOType(Enum):
     InTriOut = auto()
 
 class IOConn(Record):
+    lengths = {
+        IOType.In: 1,
+        IOType.Out: 1,
+        IOType.TriOut: 2,
+        IOType.InTriOut: 3,
+    }
+
     """TAP subblock representing the interface for an JTAG IO cell.
     It contains signal to connect to the core and to the pad
 
@@ -299,7 +306,6 @@ class ShiftReg(Record):
         ]
         super().__init__(layout, name=name, src_loc_at=src_loc_at+1)
 
-
 class TAP(Elaboratable):
     #TODO: Document TAP
     def __init__(self, *, with_reset=False, ir_width=None,
@@ -531,49 +537,41 @@ class TAP(Elaboratable):
         return ioconn
 
     def _elaborate_ios(self, *, m, capture, shift, update, bd2io, bd2core):
-        connlength = {
-            IOType.In: 1,
-            IOType.Out: 1,
-            IOType.TriOut: 2,
-            IOType.InTriOut: 3,
-        }
-        length = sum(connlength[conn._iotype] for conn in self._ios)
+        length = sum(IOConn.lengths[conn._iotype] for conn in self._ios)
         if length == 0:
             return self.bus.tdi
 
         io_sr = Signal(length)
         io_bd = Signal(length)
 
+        # Boundary scan "capture" mode.  makes I/O status available via SR
         with m.If(capture):
+            iol = []
             idx = 0
             for conn in self._ios:
-                if conn._iotype == IOType.In:
-                    m.d.posjtag += io_sr[idx].eq(conn.pad.i)
-                    idx += 1
-                elif conn._iotype == IOType.Out:
-                    m.d.posjtag += io_sr[idx].eq(conn.core.o)
-                    idx += 1
-                elif conn._iotype == IOType.TriOut:
-                    m.d.posjtag += [
-                        io_sr[idx].eq(conn.core.o),
-                        io_sr[idx+1].eq(conn.core.oe),
-                    ]
-                    idx += 2
-                elif conn._iotype == IOType.InTriOut:
-                    m.d.posjtag += [
-                        io_sr[idx].eq(conn.pad.i),
-                        io_sr[idx+1].eq(conn.core.o),
-                        io_sr[idx+2].eq(conn.core.oe),
-                    ]
-                    idx += 3
-                else:
-                    raise("Internal error")
+                # in appropriate sequence: In/TriOut has pad.i,
+                # Out.InTriOut has everything, Out and TriOut have core.o
+                if conn._iotype in [IOType.In, IOType.InTriOut]:
+                    iol.append(conn.pad.i)
+                if conn._iotype in [IOType.Out, IOType.InTriOut]:
+                    iol.append(conn.core.o)
+                if conn._iotype in [IOType.TriOut, IOType.InTriOut]:
+                    iol.append(conn.core.oe)
+                # length double-check
+                idx += IOConn.lengths[conn._iotype] # fails if wrong type
             assert idx == length, "Internal error"
+            m.d.posjtag += io_sr.eq(Cat(*iol)) # assigns all io_sr in one hit
+
+        # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
         with m.Elif(shift):
             m.d.posjtag += io_sr.eq(Cat(self.bus.tdi, io_sr[:-1]))
+
+        # "Update" mode
         with m.Elif(update):
             m.d.negjtag += io_bd.eq(io_sr)
 
+        # sets up IO (pad<->core) or in testing mode depending on requested
+        # mode, via Muxes controlled by bd2core and bd2io
         idx = 0
         for conn in self._ios:
             if conn._iotype == IOType.In: