IEEE 1500 wrapper¶
An IEEE 1500 wrapper and its wrapper serial port (WSP), as a model, as ICL, as PDL and as an integrity program. See IEEE 1500 wrappers for how the pieces fit.
from warptap import (
Wrapper1500, WbrCell, build_wsp_integrity_program, check_wsp_integrity,
replay_wsp_program, to_icl_1500, import_icl_1500,
)
wrapper = Wrapper1500(
name="blk",
chains=((WbrCell("a", "input"), WbrCell("b", "input")), (WbrCell("y", "output"),)),
)
icl = to_icl_1500(wrapper) # ICL the vendored parser accepts
assert import_icl_1500(icl) == wrapper # warptap's own shape reads back exactly
program = build_wsp_integrity_program(wrapper)
observed = replay_wsp_program(program, wrapper) # or the values your harness measured
assert check_wsp_integrity(program, observed) == [] # (step, point) pairs that differ
program_json = program.to_json() # a warptap-wsp-program file, for a tool without warptap
Model¶
warptap.wsp1500_model ¶
An IEEE 1500 wrapper and its wrapper serial port (WSP), as a model: the registers and the cycle-by-cycle behaviour every other 1500 piece of warptap (the ICL it writes, the PDL it retargets, the integrity program) is checked against.
The wrapper's registers:
- the instruction register (WIR): a shift stage, WSI into bit 0 and the last bit out to WSO, which shifts on the rising edge of WRCK while SelectWIR and ShiftWR are 1; and an update stage, the instruction in force, which takes the shift stage on the falling edge of WRCK while SelectWIR and UpdateWR are 1. WRSTN at 0 clears the update stage at once: WS_BYPASS, the functional mode. A code no instruction has acts as WS_BYPASS.
- the bypass register (WBY): one bit, WSI to WSO, which shifts while ShiftWR is 1 and captures 0 while CaptureWR is 1, the WIR not selected; cleared by WRSTN.
- the boundary register (WBR): the boundary cells, in a serial instruction WSI through them to WSO -- the wrapper chains one after another, each from its head.
An instruction is serial (WS_: the WBR is the data register WSI and WSO reach) or parallel (WP_: the WBR works on the wrapper's own scan ports), and puts the boundary cells in a mode, (INTEST, EXTEST) -- (0, 0) is functional. An input cell holds its flop in INTEST and drives the core 0 in EXTEST; an output cell holds in EXTEST and drives its port 0 in INTEST. In a serial instruction every cell also holds, its flop keeping its value, unless the WIR is deselected and CaptureWR is 1 (the cells that observe in the mode capture) or ShiftWR is 1 (the WBR shifts from WSI): a cell changes only on an event of its own (the 1500 WBR rule), not through the WIR's own shifts and updates.
A step is one tester cycle: the inputs applied, WSO strobed, then WRCK pulses (rises,
then falls) if the cycle says so. Values are 0, 1 or None, unknown: every register
starts unknown but what WRSTN clears. :class:Wsp1500Chain runs wrappers whose WSI and
WSO are chained and whose other controls are shared.
Wrapper1500
dataclass
¶
A wrapper: its boundary cells in chains (each a wrapper scan chain, head
first), the WIR's width, its instructions and its port names.
WbrCell
dataclass
¶
A boundary cell: the label of the port bit it serves and its side.
WspChainDesign
dataclass
¶
Wrappers daisy-chained on a SoC: the SoC's top module, the wrappers from
its WSI to its WSO, and pins -- each WSP role's SoC port and whether an inverter
sits between it and the wrappers (:data:warptap.icl_emit_1500.ROLES).
WspCycle
dataclass
¶
One tester cycle on the WSP: each signal's value (WRCK aside), whether WRCK pulses, and each boundary cell's functional input (its port bit, or the core's value), in serial order.
Wsp1500Sim
dataclass
¶
A wrapper's state, stepped a cycle at a time.
instruction
property
¶
instruction: Optional[str]
The instruction in force, or None while the update stage is unknown.
outputs ¶
outputs(cycle: WspCycle) -> list[Value]
Each boundary cell's functional output in cycle (to the core for an
input cell, to the port for an output cell): 0 where the mode makes it safe,
its flop where the mode holds it, else its functional input. A serial
instruction's extra holds don't show: they hold only cells the mode keeps
safe.
step ¶
step(cycle: WspCycle, wsi: object = _OWN) -> Value
Apply cycle: WSO at its strobe, returned; then its WRCK pulse. wsi
(0, 1 or None) overrides the cycle's WSI -- a chain feeds the wrapper before's
WSO.
wso ¶
wso(cycle: WspCycle) -> Value
WSO at the strobe of cycle (before its edge): the WIR's last bit when
SelectWIR is 1, else the WBR's last cell in a serial instruction, else WBY.
Wsp1500Chain ¶
Wrappers whose WSI and WSO are chained -- WSI into the first, each WSO into the next WSI, the last one's WSO the chain's -- and whose other WSP controls are the same signals.
outputs ¶
outputs(cycle: WspCycle, cfis: Optional[Sequence[tuple[Value, ...]]] = None) -> list[list[Value]]
Each wrapper's cells' functional outputs at the strobe of cycle.
step ¶
step(cycle: WspCycle, cfis: Optional[Sequence[tuple[Value, ...]]] = None) -> Value
Apply cycle to every wrapper; the chain's WSO at its strobe. Every WSO
is read before any edge, so each wrapper shifts in what its neighbour showed.
cfis: each wrapper's own functional inputs.
wso ¶
wso(cycle: WspCycle, cfis: Optional[Sequence[tuple[Value, ...]]] = None) -> Value
The chain's WSO at the strobe of cycle, without applying it.
program_cycles ¶
program_cycles(wrapper: Wrapper1500, instruction: str | int) -> list[WspCycle]
The cycles that put an instruction in force from any state -- its name, or any code: WRSTN pulsed, the code shifted into the WIR (last bit first), then updated, then the WSP idle (the WIR deselected).
ICL¶
warptap.icl_emit_1500 ¶
ICL (IEEE 1687) for an IEEE 1500 wrapper and its wrapper serial port, from a
:class:~warptap.wsp1500_model.Wrapper1500; and for a chain of wrappers on a SoC.
A wrapper is one ICL module, <name>, beside a stub of its core (<name>_core,
whose outputs the wrapper's output cells capture):
ScanInterface WSP-- WSI, WSO, ShiftWR, CaptureWR, UpdateWR, SelectWIR (aSelectPort), WRCK and WRSTN (ResetPort, active low) -- andScanInterface WPP, the wrapper's own scan access: oneChainper wrapper chain, with the wrapper scan enable.- The WIR:
ScanRegister WIR_SR(WSI in, the shift stage) andDataRegister WIR(the update stage:WriteDataSource WIR_SR, written while SelectWIR is selected, reset to WS_BYPASS), whose valuesEnum <name>_opsnames. - WBY, a one-bit
ScanRegisterthat captures 0; oneScanRegister WBR<k>per wrapper chain, the head cell the MSB and the tail the LSB, whose capture aDataMuxon the WIR chooses -- a serial instruction's cells capture their port (an input cell) or the core's output (an output cell) unless the mode holds them -- and whose scan inputserialselects: WSI (chain 0) or the chain before, in a serial instruction, else the chain's own scan port. - WSO:
WsoMux, the WIR's last bit while SelectWIR is 1, elseWdrMux: the last chain's tail in a serial instruction, else WBY. - The core's inputs and the wrapper's outputs through a
DataMuxon the WIR: 0 where the instruction's mode makes the cell safe, the cell's flop where it holds, else the functional signal.
The scan path of a ScanRegister enters its MSB and leaves its LSB (IEEE 1687, and
the vendored parser). A wrapper's WIR shifts its code in last bit first, the first bit
shifted in ending nearest WSO, so the value ICL gives an instruction is its code with its
bits reversed -- iWrite WIR WS_EXTEST shifts in the same bits the code's last bit
first does.
Attributes carry the model (warptap_*), so :mod:warptap.icl_import_1500 rebuilds
it exactly; the rest is standard ICL, which the vendored icl_parser checks.
Icl1500Error ¶
Bases: ValueError
A wrapper that can't be described as ICL.
to_icl_1500 ¶
to_icl_1500(wrapper: Wrapper1500) -> str
The ICL of one wrapper (see the module docstring), top module
wrapper.name.
to_icl_1500_chain ¶
to_icl_1500_chain(wrappers: Sequence[Wrapper1500], *, top: str, pins: Optional[Mapping[str, tuple[str, bool]]] = None) -> str
The ICL of wrappers daisy-chained on a SoC: each wrapper's module, and top
with the SoC's own WSP -- pins maps a role (ROLES) to the SoC port that
drives it and whether an inverter sits between (default: the wrapper's own port
name, direct) -- the wrappers' WSI and WSO chained, WSI at the first and WSO from the
last, under the shared controls.
warptap.icl_import_1500 ¶
The model back from the ICL :mod:warptap.icl_emit_1500 writes: a
:class:~warptap.wsp1500_model.Wrapper1500, or -- for a SoC top that chains wrappers --
a :class:~warptap.wsp1500_model.WspChainDesign.
Like :mod:warptap.icl_import for the SIB network, it takes only warptap's own shape,
and says so rather than guess: the model is read from the warptap_* attributes, then
written as ICL again, and the text must be that ICL byte for byte. Anything else -- a SIB
network, a third tool's wrapper, this ICL with its WIR or WBY edited out or an Enum value
changed -- is refused, so a program built from an imported wrapper is built from a
wrapper whose ICL is the standard description the vendored icl_parser checks.
Icl1500ImportError ¶
Bases: ValueError
ICL that isn't what warptap writes for an IEEE 1500 wrapper.
import_icl_1500 ¶
import_icl_1500(text: str) -> Union[Wrapper1500, WspChainDesign]
The wrapper text describes, or the chain of them: the model read from its
attributes, which must write exactly text again.
PDL and scan operations¶
warptap.pdl_1500 ¶
PDL (IEEE 1687) on an IEEE 1500 wrapper, or a chain of wrappers on a SoC, retargeted onto the wrapper serial port.
iReset clears the wrappers (WRSTN): every WIR is WS_BYPASS. iTarget sets the
wrapper iWrite/iRead address -- u0, u1 of a chain (the instances of
:func:warptap.icl_emit_1500.to_icl_1500_chain), or the wrapper's own name -- and a
register may be written u0.WIR to name its wrapper too. The registers:
WIR, written by an instruction name (WS_EXTEST) or its ICL value (the code with its bits reversed). OneiApplyscans every WIR of the chain at once, the far wrapper's bits first; a wrapper not written keeps its committed instruction, which must be known (aniReset, or a write). A WIR is not read: its shift stage has no capture.WBY, in an instruction whose data register is the bypass bit; andWBR0,WBR1... in a serial instruction, one per wrapper chain (the ICL registers), each by its value: the head cell the MSB, the tail the LSB. One data scan runs through whatever each wrapper's instruction selects, the far wrapper's first; a register not written shifts in 0, one not read isn't checked.
iApply turns the pending writes and reads into tap_ir scan operations --
ShiftIR for the WIRs, then ShiftDR -- appended to program (:mod:warptap.wsp_play
lowers them to cycles); iRunLoop appends idle cycles where it is called. history
keeps the statements for :func:to_pdl_1500, and :func:import_pdl_1500 reads them back.
Pdl1500Error ¶
Bases: ValueError
PDL a wrapper can't take, or can't print.
Wsp1500Interpreter ¶
See the module docstring. design: one wrapper, or a chain of them.
to_pdl_1500 ¶
to_pdl_1500(history: Sequence[Statement], design: Union[Wrapper1500, WspChainDesign]) -> str
history as PDL text, one statement a line, numbers as sized binary literals.
import_pdl_1500 ¶
import_pdl_1500(text: str, interp: Wsp1500Interpreter) -> None
Replay PDL text (:func:to_pdl_1500's subset) on interp.
warptap.wsp_ir ¶
Operations on an IEEE 1500 wrapper serial port that have no TAP counterpart.
The scan operations are :mod:warptap.tap_ir's -- ShiftIR is a WIR scan, ShiftDR
a data-register scan, Runtest idle WRCK cycles -- so the PDL layer above produces the
same operations whichever access it retargets onto. The one operation a WSP adds is
WRSTN: a cycle with the wrapper reset asserted, the only way to a known WIR.
WspReset ¶
Bases: NamedTuple
One cycle with WRSTN low and WRCK still: the wrapper's WIR update stage and WBY are cleared, WS_BYPASS in force.
warptap.wsp_play ¶
Scan operations lowered to cycles on an IEEE 1500 wrapper serial port, and played
against the model (:mod:warptap.wsp1500_model).
One row is one tester cycle: the WSP's inputs applied, WSO strobed -- against the value the operation expects there, where it expects one -- then WRCK pulsed, rising and falling (the falling edge is what the WIR's update stage takes).
- :class:
~warptap.wsp_ir.WspResetis a cycle with WRSTN low and no pulse. ShiftIR(bits, tdi)is a WIR scan: SelectWIR and ShiftWR high for each bit -- bit 0 oftdifirst -- then one cycle of SelectWIR and UpdateWR. The WIR has no capture.ShiftDR(bits, tdi)is a data-register scan, the WIR deselected: a cycle of CaptureWR,bitsof ShiftWR, a cycle of UpdateWR.Runtest(count)iscountidle cycles with WRCK pulsing;GotoStatehas no meaning here and is skipped.
tdo and mask of a scan are the TAP's: bit i of tdo is the WSO the
i-th shift cycle should strobe, where bit i of mask (all, without one) says
it is checked. cfi gives the boundary cells' functional inputs (each port bit, or the
core's output, in serial order) for every cycle.
WspPlayError ¶
Bases: ValueError
An operation a WSP can't play.
WspRow ¶
Bases: NamedTuple
A cycle, and the WSO its strobe should show (None: not checked).
to_wsp_rows ¶
to_wsp_rows(ops: Sequence[object], *, cfi: tuple[Value, ...] = ()) -> list[WspRow]
ops as WSP cycles (see the module docstring).
play ¶
play(chain: Wsp1500Chain, rows: Sequence[WspRow]) -> list[Value]
Run rows against chain; the WSO at each row's strobe.
mismatches ¶
mismatches(rows: Sequence[WspRow], observed: Sequence[Value]) -> list[int]
The rows whose strobe isn't the WSO they expect: an unknown (None) where a value is expected counts.
Integrity program¶
warptap.wsp_integrity ¶
The integrity program of an IEEE 1500 wrapper serial port: WSP cycles that exercise the
WIR, the bypass register and the boundary register, each with the value the model
(:mod:warptap.wsp1500_model) expects at every observation point -- the test a production
flow runs on the wrapper's own infrastructure, in place of scan ATPG, which holds the
instruction still and so can't.
Tests, in program order:
reset: WRSTN, then a sentinel pattern through the bypass registers, which must come outNshifts late,Nthe wrappers of the chain (WBY is one bit, and WRSTN and CaptureWR clear it).wir_length: a sentinel through the WIRs, which must come out as many shifts late as the WIRs are long; the pattern ends WS_BYPASS, so the next test starts from it.code_<bits>(u<k>_code_<bits>in a chain): every code of the WIR, one wrapper at a time with the others in bypass -- an unused code included, which acts as WS_BYPASS -- loaded, then the data register it selects scanned with a sentinel: the bypass bit, or in a serial instruction the boundary register, scanned three times so every cell and the register's length show. Each scan starts with a capture from the ports the program drives (~P, P, P: P alternates, so neighbouring cells differ) and leaves a tail in the register (0, 1, 0), so the second capture meets cells holding 0 against ports P and the third cells holding 1 against ports P: a cell that follows its port when its mode says hold, or holds when it should capture, shows in one of them. Then idle cycles, in which the mode's parallel outputs are observed.wby_hold: WBY loaded with 1 and a WIR scan of zeros, then with 0 and a WIR scan carrying ones -- WBY selected again after each update -- and WSO observed at idle: the bypass bit holds its value through a WIR scan and update.held_update: an update while the WIR is deselected, after the complement of the code in force is shifted into the WIR's shift stage (every bit differs), leaves the instruction in force.capture_update: CaptureWR with the WIR selected doesn't capture the boundary cells.
Every cycle carries what the model expects at WSO, at each wrapped output and at each
wrapper chain's scan output (:class:ObservePoint). What the program can't know -- the
core's outputs, which an output cell captures -- is no care: the model runs twice, with
those at 0 and at 1, and an observation is checked only where the runs agree. A program
is JSON, a warptap-wsp-program, which a tool without warptap can read and play.
WspIntegrityProgram
dataclass
¶
The steps, their tests and what they drive and observe. design is the model
the program was built from (None for one read from JSON).
ObservePoint
dataclass
¶
Where the program checks the wrapper: WSO, a wrapped output port (output:
the cell index of wrapper wrapper), or a wrapper chain's scan output
(scan_out: chain index). name: wso, the port's label, the scan-out
port's name -- prefixed u<k>. in a chain.
Step ¶
Bases: NamedTuple
One tester cycle: the cycle, its test, the data input ports driven (in
drive order), and the expected value at each observation point (None: no care).
WspIntegrityError ¶
Bases: WarptapError
A program that can't be built or read.
build_wsp_integrity_program ¶
build_wsp_integrity_program(design: Design, *, margin: int = 8, exhaustive_opcodes: bool = True, outputs: Optional[bool] = None, scan_outs: bool = True, drive: Optional[Sequence[str]] = None) -> WspIntegrityProgram
The integrity program of design (see the module docstring). margin: how
many sentinel bits each scan carries past the register's length; exhaustive_opcodes:
test every code of the WIR, not only the instructions' own; drive: the data input
ports the tester drives (default: all; () for wrappers whose ports are a SoC's own
nets) -- an input cell on any other captures a live value, no care.
check_wsp_integrity ¶
check_wsp_integrity(program: WspIntegrityProgram, observed: Sequence[Sequence[Value]]) -> list[tuple[int, str]]
The (step, observation point) pairs where observed differs from what the
program expects, at a care bit. An unknown (None) where a value is expected counts.
replay_wsp_program ¶
replay_wsp_program(program: WspIntegrityProgram, design: Optional[Design] = None, *, live: int = 0) -> list[list[Value]]
The values at each observation point of a program played on design (default:
the program's own), the core's outputs at live: one list per step.
observation_points ¶
observation_points(design: Design, *, outputs: Optional[bool] = None, scan_outs: bool = True) -> tuple[ObservePoint, ...]
WSO, then (outputs; default: for one wrapper, not for a chain, whose block
outputs aren't pins) each wrapped output port, then (scan_outs) each wrapper chain's
scan output.
drive_ports ¶
drive_ports(design: Design, drive: Optional[Sequence[str]] = None) -> tuple[str, ...]
The data input ports the program drives: each input cell's label, u<k>.-
prefixed in a chain, in serial order -- all of them, or (drive) only those
named; an input cell the tester doesn't drive captures a live value.