Skip to content

Network Integrity

The TCK-level program a production flow plays to test the TAP and the IJTAG network themselves -- IDCODE, the instruction register, BYPASS and every unimplemented opcode, every TAP state transition with each register held in Pause at 0 and at 1, each SIB and ScanMux arm opened alone, the network held still under SAMPLE/PRELOAD and through Pause, each WRITE instrument written and read back, a TMS reset -- with the TDO it expects from warptap's own TAP and network models. See the module docstring below for the tests in order and for how a READ instrument bound to a design signal makes its TDO bits don't-care.

from warptap import build_integrity_program, check_integrity

program = build_integrity_program(graph, root)

# Your harness: drive tms/tdi/trst_n for one TCK period, return tdo sampled before TCK rises.
observed = [tck_period(c.tms, c.tdi, c.trst_n) for c in program.cycles]

result = check_integrity(program, observed)
assert result.passed, result.failures  # the first mismatch of each failing test

program_json = program.to_json()  # a warptap-tck-program file, for a tool without warptap

warptap.tap_integrity

JTAG network-integrity patterns: the TCK-level program a production flow plays through the TAP to test the TAP itself and the IJTAG network behind it, with the TDO it expects.

The TAP and the network are usually left out of scan (they run on TCK/TRST), and are tested through TCK instead, with patterns derived from the network's own description. The program here runs, in order:

  1. reset_instruction: TRST, then a DR scan of the reset instruction's register -- IDCODE (its value, then the fed sentinel after 32 bits), or BYPASS without one;
  2. instruction_register: the IR's capture pattern, then the fed sentinel after ir_width bits (its length); the scan loads BYPASS;
  3. bypass: BYPASS's captured 0 and one-bit delay;
  4. opcode_<bits>: every unimplemented opcode behaving as BYPASS (exhaustive_opcodes);
  5. idcode: an explicit IDCODE load (with IDCODE);
  6. the TAP's own state machine and registers (tap_paths), each a raw TCK sequence: dr_paths (Run-Test/Idle held, a DR scan paused mid-register and resumed, Exit2-DR -> Update-DR, Update-DR -> Select-DR, Capture-DR -> Exit1-DR without a shift, then the register read whole again), ir_paths (the same for the IR, then Update-IR -> Select-DR), ir_capture_update (Capture-IR -> Exit1-IR -> Update-IR loads the capture pattern), select_ir_reset (Select-IR-Scan -> Test-Logic-Reset, held); idcode_hold/bypass_hold/ir_hold (each register held in Pause-DR/Pause-IR at 0 and at 1 in every bit); idcode_capture/bypass_capture (each register captured while it holds the complement of its capture value). With the rest of the program, every one of the 32 TAP state transitions is taken;
  7. network_closed: the network's instruction (EXTEST, or IJTAG_ACCESS for a TAP with an ijtag_access_opcode) with every SIB closed -- the network's length and continuity, by an over-shift probe (:mod:warptap.sib_overshift);
  8. open_<slot>: each SIB, and each ScanMux arm, opened alone from an all-closed network and probed the same way; then open_all, every SIB outside a mux at once;
  9. the network holding still (network_hold): sample_preload (SAMPLE/PRELOAD puts the network's tail on TDO for the whole scan without selecting the network; with IJTAG_ACCESS, extest and then sample_preload, each a scan through BYPASS), then network_hold (one scan through the network as the probes left it, paused holding an alternating pattern and then its complement, which ends by closing every SIB);
  10. write_readback_<instrument>: each WRITE instrument written with an alternating pattern P and read back (Capture-DR captures what it last committed), then ~P, then 0 (write_readback);
  11. tms_reset: five TMS=1 cycles (no TRST), then the reset instruction's scan again -- IEEE 1149.1's Test-Logic-Reset reload.

Every probe starts from an all-closed network: :func:~warptap.sib_retarget. stage_open_sequence leaves an already-open SIB it isn't asked about open, so each probe is preceded by one scan that closes whatever the last one opened.

The expected TDO comes from :class:~warptap.tap_model.TapModel with :class:~warptap.sib_model.SibNetworkRegister registered under the network's instruction, and under SAMPLE/PRELOAD the network's tail (:meth:~warptap.sib_model.SibNetworkRegister.tail; BYPASS with IJTAG_ACCESS), stepped through every TCK cycle. A READ instrument bound to a design signal (a live one) captures a value the model can't know, so two models run in lockstep, their live instruments capturing all 0s and all 1s; a TDO bit on which they disagree carries a live value and is don't-care (care=False). A probe's fed bits fully replace the chain's content, so a captured value reaches TDO but never a SIB's state, and the two models only ever disagree bit-for-bit. live_values pins a live instrument to a known value instead.

What the program can't see: whatever a TAP register does while another instruction is selected (every DR read starts with a capture), decodes of the opcodes Update-IR never latches (it normalizes every unimplemented one to BYPASS), TDO outside the shift states, and mostly a SIB's capture (it recaptures the state it last committed, which its shift bit normally already holds). A fault simulator grading the program finds those faults undetected.

A consumer plays :attr:IntegrityProgram.cycles one TCK period each: TMS, TDI and TRST_N applied for the period, TDO sampled before its rising edge on a shift cycle, and passes what it saw to :func:check_integrity. :meth:IntegrityProgram.to_json writes the same program as a self-contained file for a consumer without warptap (FaultFlow's jtag command).

TRST_LEAD_IN module-attribute

TRST_LEAD_IN: tuple[tuple[int, int, int], ...] = ((0, 0, 0), (0, 0, 0), (0, 0, 1))

TMS_RESET_LEAD_IN module-attribute

TMS_RESET_LEAD_IN: tuple[tuple[int, int, int], ...] = ((1, 0, 1),) * 5 + ((0, 0, 1),)

TapConfig dataclass

The TAP the program targets -- rtl/tap_core.v's parameters. Its opcodes are :mod:warptap.tap_model's (EXTEST 0, IDCODE 1, SAMPLE_PRELOAD 2, BYPASS all 1s), plus IJTAG_ACCESS at ijtag_access_opcode for a TAP built with one: the network's instruction then, and EXTEST and SAMPLE/PRELOAD decode to BYPASS.

network_opcode

network_opcode() -> int

The opcode that selects the network: EXTEST's, or IJTAG_ACCESS's.

IntegrityProgram dataclass

from_json classmethod

from_json(data: Mapping[str, Any]) -> IntegrityProgram

The inverse of :meth:to_json. The tests carry only their names -- the cycles are the program.

test_ranges

test_ranges() -> list[tuple[str, int, int]]

(name, start, stop) of each test's cycles, in program order.

to_json

to_json() -> dict[str, Any]

The program as JSON data: tap, tests (name and cycle range), and one string of 0/1 per cycle field -- tms, tdi, trst_n, shift, tdo, care -- each character one TCK cycle. tap has an ijtag_access_opcode only for a TAP with one.

IntegrityTest

Bases: NamedTuple

TckCycle

Bases: NamedTuple

IntegrityResult

Bases: NamedTuple

IntegrityFailure

Bases: NamedTuple

TapIntegrityError

Bases: WarptapError

Raised for a program that can't be built from the given network and options, or an observed TDO stream that doesn't match the program's length.

build_integrity_program

build_integrity_program(graph: PhysicalGraph, root: ModuleInstance, *, tap: TapConfig = TapConfig(), live: Optional[Iterable[str]] = None, live_values: Optional[Mapping[str, int]] = None, margin: int = 8, exhaustive_opcodes: bool = True, write_readback: bool = True, tap_paths: bool = True, network_hold: bool = True) -> IntegrityProgram

The integrity program for graph (and root, its dotted-address tree, for the write/readback tests) behind a TAP configured as tap.

live names the READ instruments whose capture depends on the design; the default is every READ instrument bound to a design signal. live_values gives the captured value of some of them, which makes their bits care bits. margin is the number of sentinel bits fed past each register's length (at least 1: a register's length shows only when a fed bit comes back out). exhaustive_opcodes, write_readback, tap_paths and network_hold each include a group of tests (see the module docstring).

check_integrity

check_integrity(program: IntegrityProgram, observed_tdo: Sequence[object]) -> IntegrityResult

Compare observed_tdo (one TDO value per program cycle) with the expected TDO on every care cycle, naming the first mismatch of each failing test.

select_instruction

select_instruction(opcode: int, *, ir_width: int = DEFAULT_IR_WIDTH) -> list[_IrOp]

Run-Test/Idle -> shift opcode into the instruction register -> Run-Test/Idle.