Docs / Test Point Insertion Guide

TPI inserts observation and control logic so hard-to-test internal signals become easier to control and observe.

What gets added

Depending on mode and selected points, the generated design can include:

Minimal workflow

python3 opentest analyze_and_add_tp -i <design.json> --scoap -t 50 -m 10 -v

Key parameters

Option Meaning Typical value
-t, --threshold Minimum testability threshold for selecting weak signals 50
-m, --max-points Maximum number of test points to insert 10
force_type Force only observation or only control insertion Python API only (insert_testpoints_yosys(force_type=...)); not yet CLI-exposed
--dont-touch, --dont-touch-file Nets or cell instances to leave alone see below
--area-budget Cap on total test point cell area see below
--obs-share Observation points XORed onto each output port 1 (off)
-v, --verbose Write detailed analysis logs and reports recommended

Constraints

These apply after candidate selection, so every --tpi-algorithm respects them.

Don’t-touch. Each pattern is a shell glob, case-sensitive, and is also compared literally first, so bus[3] means that exact bit. Plain patterns match net names, including every alias a net has; cell:<glob> matches cell instance names, e.g. cell:u_ip.* for a flattened IP block. A net is excluded when one of its names matches, or when a matching cell drives or reads it. Excluded nets are dropped before -m is applied, so they never use up the point budget, and each shows up in the report with reason Don't-touch. Use --dont-touch-file for a long list: one pattern per line, # comments allowed.

Area budget. --area-budget caps the summed area of every cell TPI inserts, in the Liberty area units of the chosen --tech. Candidates are taken in rank order; one that would overrun the budget is skipped (reason Exceeded area budget) and cheaper points further down can still go in. Costs per point: observation = one buffer; force-1 control = one OR; force-0 control = one AND, plus the shared inverter on the first one; legacy mux control = one mux (plus an inverter on PDKs whose mux inverts). Given --area-budget without -m, the budget alone limits how many points go in. The report’s area.used is always filled in, budget or not.

Observation sharing. --obs-share N XORs up to N observation points onto one output port (tp_obs_grp, tp_obs_grp_1, …) through a balanced tree of 2-input XOR cells, in place of one buffered port per point. N points then cost N - 1 XORs and one pin, against N buffers and N pins. A group left with a single point gets a normal buffered port. The trade-off is parity aliasing: fault effects reaching an even number of nets in the same group at once cancel at the port. With sharing on, the _tp_cells.json sidecar also lists the XOR cell (FaultFlow gate type XOR2).

Simulation checklist

Drive all DFT/test inputs in your testbench:

reg test_mode;
reg tp_ctrl_0;
reg tp_ctrl_1;

initial begin
    test_mode = 1'b0;
    tp_ctrl_0 = 1'b0;
    tp_ctrl_1 = 1'b0;
end

Also ensure your circuit reset sequence initializes all state elements.

Expected behavior

  1. With test_mode = 0, functional outputs should match the original design.
  2. Observation outputs should mirror internal nodes without destabilizing normal logic.
  3. Verbose mode should produce per-run logs and reports under results/.

Troubleshooting

  1. Getting Started
  2. Examples
  3. Command Reference