nmigen explicit imports
[c4m-jtag.git] / c4m / nmigen / jtag / tap.py
index 44cae0453869f971b9f587e5fd5abfa06cc8701d..c10ff3a7c59dc476a09a7146fa65d9f1b00ee5cf 100755 (executable)
@@ -1,10 +1,9 @@
-#!/bin/env python3
+#!/usr/bin/env python3
 import os, textwrap
 from enum import Enum, auto
 
-from nmigen import *
-from nmigen.build import *
-from nmigen.lib.io import *
+from nmigen import (Elaboratable, Signal, Module, ClockDomain, Cat, Record,
+                    Const, Mux)
 from nmigen.hdl.rec import Direction, Layout
 from nmigen.tracer import get_var_name
 
@@ -26,6 +25,7 @@ class _FSM(Elaboratable):
         self.shift = Signal()
         self.update = Signal()
 
+        # JTAG uses both edges of the incoming clock (TCK). set them up here
         self.posjtag = ClockDomain("posjtag", local=True)
         self.negjtag = ClockDomain("negjtag", local=True, clk_edge="neg")
 
@@ -119,6 +119,7 @@ class _FSM(Elaboratable):
 
         return m
 
+
 class _IRBlock(Elaboratable):
     """TAP subblock for handling the IR shift register"""
     def __init__(self, *, ir_width, cmd_idcode,
@@ -151,12 +152,14 @@ class _IRBlock(Elaboratable):
 
         return m
 
+
 class IOType(Enum):
     In = auto()
     Out = auto()
     TriOut = auto()
     InTriOut = auto()
 
+
 class IOConn(Record):
     """TAP subblock representing the interface for an JTAG IO cell.
     It contains signal to connect to the core and to the pad
@@ -198,6 +201,7 @@ class IOConn(Record):
 
         self._iotype = iotype
 
+
 class _IDBypassBlock(Elaboratable):
     """TAP subblock for the ID shift register"""
     def __init__(self, *, manufacturer_id, part_number, version,
@@ -326,7 +330,6 @@ class TAP(Elaboratable):
         self._srs = []
         self._wbs = []
 
-
     def elaborate(self, platform):
         m = Module()
 
@@ -349,6 +352,7 @@ class TAP(Elaboratable):
         m.domains.posjtag = fsm.posjtag
         m.domains.negjtag = fsm.negjtag
 
+        # IR block
         select_ir = fsm.isir
         m.submodules._irblock = irblock = _IRBlock(
             ir_width=ir_width, cmd_idcode=cmd_idcode, tdi=self.bus.tdi,
@@ -359,6 +363,7 @@ class TAP(Elaboratable):
         )
         ir = irblock.ir
 
+        # ID block
         select_id = fsm.isdr & ((ir == cmd_idcode) | (ir == cmd_bypass))
         m.submodules._idblock = idblock = _IDBypassBlock(
             manufacturer_id=self._manufacturer_id, part_number=self._part_number,
@@ -370,6 +375,7 @@ class TAP(Elaboratable):
             name=self.name+"_id",
         )
 
+        # IO (Boundary scan) block
         io_capture = Signal()
         io_shift = Signal()
         io_update = Signal()
@@ -391,6 +397,7 @@ class TAP(Elaboratable):
             bd2io=io_bd2io, bd2core=io_bd2core,
         )
 
+        # chain tdo: select as appropriate, to go into into shiftregs
         tdo = Signal(name=self.name+"_tdo")
         with m.If(select_ir):
             m.d.comb += tdo.eq(irblock.tdo)
@@ -399,10 +406,13 @@ class TAP(Elaboratable):
         with m.Elif(select_io):
             m.d.comb += tdo.eq(io_tdo)
 
+        # shiftregs block
         self._elaborate_shiftregs(
             m, capture=fsm.capture, shift=fsm.shift, update=fsm.update,
             ir=irblock.ir, tdo_jtag=tdo
         )
+
+        # wishbone
         self._elaborate_wishbones(m)
 
         return m
@@ -432,10 +442,13 @@ class TAP(Elaboratable):
             IOType.InTriOut: 3,
         }
         length = sum(connlength[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):
             idx = 0
             for conn in self._ios:
@@ -461,11 +474,17 @@ class TAP(Elaboratable):
                 else:
                     raise("Internal error")
             assert idx == length, "Internal error"
+
+        # "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:
@@ -493,7 +512,6 @@ class TAP(Elaboratable):
 
         return io_sr[-1]
 
-
     def add_shiftreg(self, *, ircode, length, domain="sync", name=None, src_loc_at=0):
         """Add a shift register to the JTAG interface