From d7a159e84c2ce39b68d4e90ffdface2be870839f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 12:56:41 +0700 Subject: [PATCH] analog M4d-b: the delay cell remembers its last edge -- repeated clkc falls within 1.8 % of ngspice PSP103, CK edges within 1 % (Closes #10848) The gate-level SAR logic of M4d had a stateless delay cell: a table of settled delays. In the self-timed loop nothing settles, and the repeated clkc falls came 13.2 ns after Valid against ngspice's 7.0 ns (83 to 90 % late). - The state of the nor3 output n1 and of the delay cell output n2 is their AGE, the time since each last crossed the other way. Four tables of age against delay (SL_HIST, 11 measured points each) from 21 calibration chains of the new specs/analog/decks/sar_delay_hist.cir scale the settled delays of the nor3 fall and rise and of the delay cell rise and fall; the age is ms[SL_TCH + g]. - Held-out check: 7 pulse trains (other spacings, none in the tables) are reproduced at every fall and rise within 5.1 %, the settled ones within 1.7 %. - Negative control: ms[SL_HON] = 0 (the stateless cell) fails the repeated-fall check by 83 to 90 % (180 % at the 15 / 15 ns pace). - Last fall with CK1 up as well: SL_C2_PM, fitted at one point. - Inverter after the delay cell: ngspice's delay for a slow edge (SL_IV_R/F). - CK edges (were 17 % early): the fight of the skew window (a node that held the weak value stays until the weak driver lets go) and the tgate In terminal load (SL_TG_IN_LOAD, fitted); CK11 .. CK2 within 1 %, CK1 3 % late. - SL_REPEAT_F_BOUND_PM = 1300 and SL_REPEAT_R_BOUND_PM removed; every clkc edge is held to SL_CLKC_BOUND_PM = 8 %. - The SAR_GOLDEN_SUBCKTS extraction line in the header and two decks dropped every `.ends`; fixed. Co-Authored-By: Claude Sonnet 5.5 --- .trinity/seals/analog_AnalogSarLogic.json | 16 +- specs/analog/decks/sar_delay_hist.cir | 438 ++++++++++++++++++ specs/analog/decks/sar_gate_arcs.cir | 2 +- specs/analog/decks/sar_logic_ref.cir | 2 +- specs/analog/sar_logic.t27 | 539 ++++++++++++++++++++-- 5 files changed, 937 insertions(+), 60 deletions(-) create mode 100644 specs/analog/decks/sar_delay_hist.cir diff --git a/.trinity/seals/analog_AnalogSarLogic.json b/.trinity/seals/analog_AnalogSarLogic.json index a51ccd3f5c..9d2dfa1fa0 100644 --- a/.trinity/seals/analog_AnalogSarLogic.json +++ b/.trinity/seals/analog_AnalogSarLogic.json @@ -7,23 +7,23 @@ } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:4c6e5eb8b9dcad8cd7f0baa5fa69623cf901104be289d236af89bf01338d85c4", - "gen_hash_rust": "sha256:3ccf030691186395e647b86349eec96e00220eda2c501145b6fc4b5cbab319b2", - "gen_hash_verilog": "sha256:eb217c9f971878de543a4e8e92bf159c3e5e00550854092b12ad0d1fe57339a7", - "gen_hash_zig": "sha256:489a6b9840a98f636d622dc562c25ec27bd73b9a1cbe0d163cb8f49340b89966", + "gen_hash_c": "sha256:83035e6bf581dec672e7aefedbe7cab8f99e557b62d2494c67be94995b73542e", + "gen_hash_rust": "sha256:9e98bdb17f009c7c48cd92895be3016da5807101f99b1eb1bf06f8e09d15ec21", + "gen_hash_verilog": "sha256:a5297d3fb22d6df5536ed434c6d505657b416d3395e0518ef3fff379cded5c47", + "gen_hash_zig": "sha256:3b32ad1dad54a68639d3d9f9eee05fdd9a75927ef3baec0df89e84e64432d5c0", "module": "AnalogSarLogic", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-19T04:37:36Z", + "sealed_at": "2026-10-19T05:55:55Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:ee58c543c573cc66fbafa5a3d28bd647c71aea6136a75f787b88bc7e8ddbade5", + "spec_hash": "sha256:80880ba02bc8f161cc968121104211a58f6f6c4d092c7d26a0a5e129f18ddb7f", "spec_path": "specs/analog/sar_logic.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 12, - "total": 12, + "passed": 17, + "total": 17, "vacuous": 0 }, "toolchain": { diff --git a/specs/analog/decks/sar_delay_hist.cir b/specs/analog/decks/sar_delay_hist.cir new file mode 100644 index 0000000000..86f81bf3eb --- /dev/null +++ b/specs/analog/decks/sar_delay_hist.cir @@ -0,0 +1,438 @@ +SAR clock_gen delay chain history: nor3, delay_cell and inverter of the golden SAR deck driven by Valid pulse trains of many spacings, PSP103 tt at 50 C +* specs/analog/decks/sar_delay_hist.cir -- reference data for specs/analog/sar_logic.t27 (M4d-b, #10848, epic #10486). The delay cell of clock_gen is not a +* settled delay: its input (the nor3 output, a net with 3 pF of long gate) and its output (the net the inverter reads) are still moving when the next Valid +* edge comes, so a delay depends on how long ago the same node last crossed the other way. This deck measures it. Every chain is the clock_gen chain of the +* golden SAR deck (uberWAVE wp2-parser/golden/top.spice, GPL-2.0: fetched at run time, never vendored): nor3(clks = 0, Valid, CK1 = 0) -> delay_cell (trim code +* 000, the golden top's) -> inverter, 8 fF on clkc, each with its own ideal Valid source (the 12 fF of the golden top sit on an ideal source and do not matter). +* Valid starts high (the circuit at rest, n1 low, n2 high), falls at 1.1 ns (the clks fall of the golden run: n1 starts to rise), rises for the first time at +* 49.7 ns (48.6 ns later, as in the golden run) and then in pulses of high time Wh and low time Wl, edges 0.2 ns, all times the 50 % points. +* - cl: Wh = 30 ns, Wl = 16 .. 120 ns, four pulses; ch: Wl = 30 ns, Wh = 14 .. 120 ns, four pulses. CALIBRATION: sar_logic.t27's history tables +* (SL_HIST) are read from the fourth pulse of these 21 chains. +* - h01 .. h07: six pulses of other spacings, h01 the golden pace (20.2 / 19.8). HELD OUT: no table entry comes from them. +* - k01: the golden pace with eleven pulses and CK1 (the third input of the nor3) rising 0.654 ns after the eleventh Valid rise and staying up, as in the +* golden run (sar_logic_ref.cir: CK1 rises 654 ps after the eleventh edge). +* Paths are NOT in this file: ngspice reads IHP_PDK (the IHP-Open-PDK checkout), IHP_OSDI (the directory with the compiled psp103.osdi and psp103_nqs.osdi) and +* SAR_GOLDEN_SUBCKTS (the subcircuit section of the golden deck, made at run time: +* sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^\.(end|global)([[:space:]]|$)' > $SAR_GOLDEN_SUBCKTS ) from the environment. +* Run: IHP_PDK= IHP_OSDI= SAR_GOLDEN_SUBCKTS= ngspice -b sar_delay_hist.cir (ngspice-47) +* It prints one line per crossing at 0.75 V, = , name = _: net n1 (nor3 output), n2 (delay cell output) or ck (clkc), r|f the +* edge, index the count from 1 of that net's edges of that direction. n1 and n2 rise first when Valid first falls (index 1), so after Valid pulse k (from 0) the +* falling edge of n1 is index k + 1 and its rising edge index k + 2; the same for n2 and ck. +.lib $IHP_PDK/ihp-sg13g2/libs.tech/ngspice/models/cornerMOSlv.lib mos_tt +.include $SAR_GOLDEN_SUBCKTS +VDD vdd 0 1.5 +Vlo lo 0 0 +Vv_c016l v_c016l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 95.6n 0 95.8n 1.5 125.6n 1.5 125.8n 0 141.6n 0 141.8n 1.5 171.6n 1.5 171.8n 0 187.6n 0 187.8n 1.5 217.6n 1.5 217.8n 0) +xn_c016l vdd 0 n1_c016l lo v_c016l lo nor3 +xd_c016l n2_c016l vdd 0 n1_c016l lo lo lo delay_cell +xi_c016l n2_c016l vdd 0 ck_c016l inverter +C_c016l ck_c016l 0 8f +Vv_c018l v_c018l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 97.6n 0 97.8n 1.5 127.6n 1.5 127.8n 0 145.6n 0 145.8n 1.5 175.6n 1.5 175.8n 0 193.6n 0 193.8n 1.5 223.6n 1.5 223.8n 0) +xn_c018l vdd 0 n1_c018l lo v_c018l lo nor3 +xd_c018l n2_c018l vdd 0 n1_c018l lo lo lo delay_cell +xi_c018l n2_c018l vdd 0 ck_c018l inverter +C_c018l ck_c018l 0 8f +Vv_c020l v_c020l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 99.6n 0 99.8n 1.5 129.6n 1.5 129.8n 0 149.6n 0 149.8n 1.5 179.6n 1.5 179.8n 0 199.6n 0 199.8n 1.5 229.6n 1.5 229.8n 0) +xn_c020l vdd 0 n1_c020l lo v_c020l lo nor3 +xd_c020l n2_c020l vdd 0 n1_c020l lo lo lo delay_cell +xi_c020l n2_c020l vdd 0 ck_c020l inverter +C_c020l ck_c020l 0 8f +Vv_c023l v_c023l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 102.6n 0 102.8n 1.5 132.6n 1.5 132.8n 0 155.6n 0 155.8n 1.5 185.6n 1.5 185.8n 0 208.6n 0 208.8n 1.5 238.6n 1.5 238.8n 0) +xn_c023l vdd 0 n1_c023l lo v_c023l lo nor3 +xd_c023l n2_c023l vdd 0 n1_c023l lo lo lo delay_cell +xi_c023l n2_c023l vdd 0 ck_c023l inverter +C_c023l ck_c023l 0 8f +Vv_c027l v_c027l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 106.6n 0 106.8n 1.5 136.6n 1.5 136.8n 0 163.6n 0 163.8n 1.5 193.6n 1.5 193.8n 0 220.6n 0 220.8n 1.5 250.6n 1.5 250.8n 0) +xn_c027l vdd 0 n1_c027l lo v_c027l lo nor3 +xd_c027l n2_c027l vdd 0 n1_c027l lo lo lo delay_cell +xi_c027l n2_c027l vdd 0 ck_c027l inverter +C_c027l ck_c027l 0 8f +Vv_c032l v_c032l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 111.6n 0 111.8n 1.5 141.6n 1.5 141.8n 0 173.6n 0 173.8n 1.5 203.6n 1.5 203.8n 0 235.6n 0 235.8n 1.5 265.6n 1.5 265.8n 0) +xn_c032l vdd 0 n1_c032l lo v_c032l lo nor3 +xd_c032l n2_c032l vdd 0 n1_c032l lo lo lo delay_cell +xi_c032l n2_c032l vdd 0 ck_c032l inverter +C_c032l ck_c032l 0 8f +Vv_c040l v_c040l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 119.6n 0 119.8n 1.5 149.6n 1.5 149.8n 0 189.6n 0 189.8n 1.5 219.6n 1.5 219.8n 0 259.6n 0 259.8n 1.5 289.6n 1.5 289.8n 0) +xn_c040l vdd 0 n1_c040l lo v_c040l lo nor3 +xd_c040l n2_c040l vdd 0 n1_c040l lo lo lo delay_cell +xi_c040l n2_c040l vdd 0 ck_c040l inverter +C_c040l ck_c040l 0 8f +Vv_c055l v_c055l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 134.6n 0 134.8n 1.5 164.6n 1.5 164.8n 0 219.6n 0 219.8n 1.5 249.6n 1.5 249.8n 0 304.6n 0 304.8n 1.5 334.6n 1.5 334.8n 0) +xn_c055l vdd 0 n1_c055l lo v_c055l lo nor3 +xd_c055l n2_c055l vdd 0 n1_c055l lo lo lo delay_cell +xi_c055l n2_c055l vdd 0 ck_c055l inverter +C_c055l ck_c055l 0 8f +Vv_c080l v_c080l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 159.6n 0 159.8n 1.5 189.6n 1.5 189.8n 0 269.6n 0 269.8n 1.5 299.6n 1.5 299.8n 0 379.6n 0 379.8n 1.5 409.6n 1.5 409.8n 0) +xn_c080l vdd 0 n1_c080l lo v_c080l lo nor3 +xd_c080l n2_c080l vdd 0 n1_c080l lo lo lo delay_cell +xi_c080l n2_c080l vdd 0 ck_c080l inverter +C_c080l ck_c080l 0 8f +Vv_c120l v_c120l 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 199.6n 0 199.8n 1.5 229.6n 1.5 229.8n 0 349.6n 0 349.8n 1.5 379.6n 1.5 379.8n 0 499.6n 0 499.8n 1.5 529.6n 1.5 529.8n 0) +xn_c120l vdd 0 n1_c120l lo v_c120l lo nor3 +xd_c120l n2_c120l vdd 0 n1_c120l lo lo lo delay_cell +xi_c120l n2_c120l vdd 0 ck_c120l inverter +C_c120l ck_c120l 0 8f +Vv_c014h v_c014h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 63.6n 1.5 63.8n 0 93.6n 0 93.8n 1.5 107.6n 1.5 107.8n 0 137.6n 0 137.8n 1.5 151.6n 1.5 151.8n 0 181.6n 0 181.8n 1.5 195.6n 1.5 195.8n 0) +xn_c014h vdd 0 n1_c014h lo v_c014h lo nor3 +xd_c014h n2_c014h vdd 0 n1_c014h lo lo lo delay_cell +xi_c014h n2_c014h vdd 0 ck_c014h inverter +C_c014h ck_c014h 0 8f +Vv_c016h v_c016h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 65.6n 1.5 65.8n 0 95.6n 0 95.8n 1.5 111.6n 1.5 111.8n 0 141.6n 0 141.8n 1.5 157.6n 1.5 157.8n 0 187.6n 0 187.8n 1.5 203.6n 1.5 203.8n 0) +xn_c016h vdd 0 n1_c016h lo v_c016h lo nor3 +xd_c016h n2_c016h vdd 0 n1_c016h lo lo lo delay_cell +xi_c016h n2_c016h vdd 0 ck_c016h inverter +C_c016h ck_c016h 0 8f +Vv_c018h v_c018h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 67.6n 1.5 67.8n 0 97.6n 0 97.8n 1.5 115.6n 1.5 115.8n 0 145.6n 0 145.8n 1.5 163.6n 1.5 163.8n 0 193.6n 0 193.8n 1.5 211.6n 1.5 211.8n 0) +xn_c018h vdd 0 n1_c018h lo v_c018h lo nor3 +xd_c018h n2_c018h vdd 0 n1_c018h lo lo lo delay_cell +xi_c018h n2_c018h vdd 0 ck_c018h inverter +C_c018h ck_c018h 0 8f +Vv_c020h v_c020h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 69.6n 1.5 69.8n 0 99.6n 0 99.8n 1.5 119.6n 1.5 119.8n 0 149.6n 0 149.8n 1.5 169.6n 1.5 169.8n 0 199.6n 0 199.8n 1.5 219.6n 1.5 219.8n 0) +xn_c020h vdd 0 n1_c020h lo v_c020h lo nor3 +xd_c020h n2_c020h vdd 0 n1_c020h lo lo lo delay_cell +xi_c020h n2_c020h vdd 0 ck_c020h inverter +C_c020h ck_c020h 0 8f +Vv_c023h v_c023h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 72.6n 1.5 72.8n 0 102.6n 0 102.8n 1.5 125.6n 1.5 125.8n 0 155.6n 0 155.8n 1.5 178.6n 1.5 178.8n 0 208.6n 0 208.8n 1.5 231.6n 1.5 231.8n 0) +xn_c023h vdd 0 n1_c023h lo v_c023h lo nor3 +xd_c023h n2_c023h vdd 0 n1_c023h lo lo lo delay_cell +xi_c023h n2_c023h vdd 0 ck_c023h inverter +C_c023h ck_c023h 0 8f +Vv_c027h v_c027h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 76.6n 1.5 76.8n 0 106.6n 0 106.8n 1.5 133.6n 1.5 133.8n 0 163.6n 0 163.8n 1.5 190.6n 1.5 190.8n 0 220.6n 0 220.8n 1.5 247.6n 1.5 247.8n 0) +xn_c027h vdd 0 n1_c027h lo v_c027h lo nor3 +xd_c027h n2_c027h vdd 0 n1_c027h lo lo lo delay_cell +xi_c027h n2_c027h vdd 0 ck_c027h inverter +C_c027h ck_c027h 0 8f +Vv_c032h v_c032h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 81.6n 1.5 81.8n 0 111.6n 0 111.8n 1.5 143.6n 1.5 143.8n 0 173.6n 0 173.8n 1.5 205.6n 1.5 205.8n 0 235.6n 0 235.8n 1.5 267.6n 1.5 267.8n 0) +xn_c032h vdd 0 n1_c032h lo v_c032h lo nor3 +xd_c032h n2_c032h vdd 0 n1_c032h lo lo lo delay_cell +xi_c032h n2_c032h vdd 0 ck_c032h inverter +C_c032h ck_c032h 0 8f +Vv_c040h v_c040h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 89.6n 1.5 89.8n 0 119.6n 0 119.8n 1.5 159.6n 1.5 159.8n 0 189.6n 0 189.8n 1.5 229.6n 1.5 229.8n 0 259.6n 0 259.8n 1.5 299.6n 1.5 299.8n 0) +xn_c040h vdd 0 n1_c040h lo v_c040h lo nor3 +xd_c040h n2_c040h vdd 0 n1_c040h lo lo lo delay_cell +xi_c040h n2_c040h vdd 0 ck_c040h inverter +C_c040h ck_c040h 0 8f +Vv_c055h v_c055h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 104.6n 1.5 104.8n 0 134.6n 0 134.8n 1.5 189.6n 1.5 189.8n 0 219.6n 0 219.8n 1.5 274.6n 1.5 274.8n 0 304.6n 0 304.8n 1.5 359.6n 1.5 359.8n 0) +xn_c055h vdd 0 n1_c055h lo v_c055h lo nor3 +xd_c055h n2_c055h vdd 0 n1_c055h lo lo lo delay_cell +xi_c055h n2_c055h vdd 0 ck_c055h inverter +C_c055h ck_c055h 0 8f +Vv_c080h v_c080h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 129.6n 1.5 129.8n 0 159.6n 0 159.8n 1.5 239.6n 1.5 239.8n 0 269.6n 0 269.8n 1.5 349.6n 1.5 349.8n 0 379.6n 0 379.8n 1.5 459.6n 1.5 459.8n 0) +xn_c080h vdd 0 n1_c080h lo v_c080h lo nor3 +xd_c080h n2_c080h vdd 0 n1_c080h lo lo lo delay_cell +xi_c080h n2_c080h vdd 0 ck_c080h inverter +C_c080h ck_c080h 0 8f +Vv_c120h v_c120h 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 169.6n 1.5 169.8n 0 199.6n 0 199.8n 1.5 319.6n 1.5 319.8n 0 349.6n 0 349.8n 1.5 469.6n 1.5 469.8n 0 499.6n 0 499.8n 1.5 619.6n 1.5 619.8n 0) +xn_c120h vdd 0 n1_c120h lo v_c120h lo nor3 +xd_c120h n2_c120h vdd 0 n1_c120h lo lo lo delay_cell +xi_c120h n2_c120h vdd 0 ck_c120h inverter +C_c120h ck_c120h 0 8f +Vv_h01 v_h01 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 69.8n 1.5 70n 0 89.6n 0 89.8n 1.5 109.8n 1.5 110n 0 129.6n 0 129.8n 1.5 149.8n 1.5 150n 0 169.6n 0 169.8n 1.5 189.8n 1.5 190n 0 209.6n 0 209.8n 1.5 229.8n 1.5 230n 0 249.6n 0 249.8n 1.5 269.8n 1.5 270n 0) +xn_h01 vdd 0 n1_h01 lo v_h01 lo nor3 +xd_h01 n2_h01 vdd 0 n1_h01 lo lo lo delay_cell +xi_h01 n2_h01 vdd 0 ck_h01 inverter +C_h01 ck_h01 0 8f +Vv_h02 v_h02 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 64.6n 1.5 64.8n 0 79.6n 0 79.8n 1.5 94.6n 1.5 94.8n 0 109.6n 0 109.8n 1.5 124.6n 1.5 124.8n 0 139.6n 0 139.8n 1.5 154.6n 1.5 154.8n 0 169.6n 0 169.8n 1.5 184.6n 1.5 184.8n 0 199.6n 0 199.8n 1.5 214.6n 1.5 214.8n 0) +xn_h02 vdd 0 n1_h02 lo v_h02 lo nor3 +xd_h02 n2_h02 vdd 0 n1_h02 lo lo lo delay_cell +xi_h02 n2_h02 vdd 0 ck_h02 inverter +C_h02 ck_h02 0 8f +Vv_h03 v_h03 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 74.6n 1.5 74.8n 0 99.6n 0 99.8n 1.5 124.6n 1.5 124.8n 0 149.6n 0 149.8n 1.5 174.6n 1.5 174.8n 0 199.6n 0 199.8n 1.5 224.6n 1.5 224.8n 0 249.6n 0 249.8n 1.5 274.6n 1.5 274.8n 0 299.6n 0 299.8n 1.5 324.6n 1.5 324.8n 0) +xn_h03 vdd 0 n1_h03 lo v_h03 lo nor3 +xd_h03 n2_h03 vdd 0 n1_h03 lo lo lo delay_cell +xi_h03 n2_h03 vdd 0 ck_h03 inverter +C_h03 ck_h03 0 8f +Vv_h04 v_h04 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 67.6n 1.5 67.8n 0 89.6n 0 89.8n 1.5 107.6n 1.5 107.8n 0 129.6n 0 129.8n 1.5 147.6n 1.5 147.8n 0 169.6n 0 169.8n 1.5 187.6n 1.5 187.8n 0 209.6n 0 209.8n 1.5 227.6n 1.5 227.8n 0 249.6n 0 249.8n 1.5 267.6n 1.5 267.8n 0) +xn_h04 vdd 0 n1_h04 lo v_h04 lo nor3 +xd_h04 n2_h04 vdd 0 n1_h04 lo lo lo delay_cell +xi_h04 n2_h04 vdd 0 ck_h04 inverter +C_h04 ck_h04 0 8f +Vv_h05 v_h05 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 73.6n 1.5 73.8n 0 89.6n 0 89.8n 1.5 113.6n 1.5 113.8n 0 129.6n 0 129.8n 1.5 153.6n 1.5 153.8n 0 169.6n 0 169.8n 1.5 193.6n 1.5 193.8n 0 209.6n 0 209.8n 1.5 233.6n 1.5 233.8n 0 249.6n 0 249.8n 1.5 273.6n 1.5 273.8n 0) +xn_h05 vdd 0 n1_h05 lo v_h05 lo nor3 +xd_h05 n2_h05 vdd 0 n1_h05 lo lo lo delay_cell +xi_h05 n2_h05 vdd 0 ck_h05 inverter +C_h05 ck_h05 0 8f +Vv_h06 v_h06 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 79.6n 1.5 79.8n 0 99.6n 0 99.8n 1.5 129.6n 1.5 129.8n 0 149.6n 0 149.8n 1.5 179.6n 1.5 179.8n 0 199.6n 0 199.8n 1.5 229.6n 1.5 229.8n 0 249.6n 0 249.8n 1.5 279.6n 1.5 279.8n 0 299.6n 0 299.8n 1.5 329.6n 1.5 329.8n 0) +xn_h06 vdd 0 n1_h06 lo v_h06 lo nor3 +xd_h06 n2_h06 vdd 0 n1_h06 lo lo lo delay_cell +xi_h06 n2_h06 vdd 0 ck_h06 inverter +C_h06 ck_h06 0 8f +Vv_h07 v_h07 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 71.6n 1.5 71.8n 0 109.6n 0 109.8n 1.5 131.6n 1.5 131.8n 0 169.6n 0 169.8n 1.5 191.6n 1.5 191.8n 0 229.6n 0 229.8n 1.5 251.6n 1.5 251.8n 0 289.6n 0 289.8n 1.5 311.6n 1.5 311.8n 0 349.6n 0 349.8n 1.5 371.6n 1.5 371.8n 0) +xn_h07 vdd 0 n1_h07 lo v_h07 lo nor3 +xd_h07 n2_h07 vdd 0 n1_h07 lo lo lo delay_cell +xi_h07 n2_h07 vdd 0 ck_h07 inverter +C_h07 ck_h07 0 8f +Vv_k01 v_k01 0 PWL(0n 1.5 1n 1.5 1.2n 0 49.6n 0 49.8n 1.5 69.8n 1.5 70n 0 89.6n 0 89.8n 1.5 109.8n 1.5 110n 0 129.6n 0 129.8n 1.5 149.8n 1.5 150n 0 169.6n 0 169.8n 1.5 189.8n 1.5 190n 0 209.6n 0 209.8n 1.5 229.8n 1.5 230n 0 249.6n 0 249.8n 1.5 269.8n 1.5 270n 0 289.6n 0 289.8n 1.5 309.8n 1.5 310n 0 329.6n 0 329.8n 1.5 349.8n 1.5 350n 0 369.6n 0 369.8n 1.5 389.8n 1.5 390n 0 409.6n 0 409.8n 1.5 429.8n 1.5 430n 0 449.6n 0 449.8n 1.5 469.8n 1.5 470n 0) +Vc_k01 c_k01 0 PWL(0 0 450.254n 0 450.454n 1.5) +xn_k01 vdd 0 n1_k01 lo v_k01 c_k01 nor3 +xd_k01 n2_k01 vdd 0 n1_k01 lo lo lo delay_cell +xi_k01 n2_k01 vdd 0 ck_k01 inverter +C_k01 ck_k01 0 8f +.temp 50 +.options reltol=1e-4 +.tran 5p 654n 0 50p +.control +option klu +set num_threads=8 +pre_osdi $IHP_OSDI/psp103.osdi +pre_osdi $IHP_OSDI/psp103_nqs.osdi +set numdgt=7 +run +meas tran c016l_n1f4 when v(n1_c016l)=0.75 fall=4 +meas tran c016l_n1r4 when v(n1_c016l)=0.75 rise=4 +meas tran c016l_n1r5 when v(n1_c016l)=0.75 rise=5 +meas tran c016l_n2r4 when v(n2_c016l)=0.75 rise=4 +meas tran c016l_n2f4 when v(n2_c016l)=0.75 fall=4 +meas tran c016l_n2f5 when v(n2_c016l)=0.75 fall=5 +meas tran c016l_ckf4 when v(ck_c016l)=0.75 fall=4 +meas tran c016l_ckr5 when v(ck_c016l)=0.75 rise=5 +meas tran c018l_n1f4 when v(n1_c018l)=0.75 fall=4 +meas tran c018l_n1r4 when v(n1_c018l)=0.75 rise=4 +meas tran c018l_n1r5 when v(n1_c018l)=0.75 rise=5 +meas tran c018l_n2r4 when v(n2_c018l)=0.75 rise=4 +meas tran c018l_n2f4 when v(n2_c018l)=0.75 fall=4 +meas tran c018l_n2f5 when v(n2_c018l)=0.75 fall=5 +meas tran c018l_ckf4 when v(ck_c018l)=0.75 fall=4 +meas tran c018l_ckr5 when v(ck_c018l)=0.75 rise=5 +meas tran c020l_n1f4 when v(n1_c020l)=0.75 fall=4 +meas tran c020l_n1r4 when v(n1_c020l)=0.75 rise=4 +meas tran c020l_n1r5 when v(n1_c020l)=0.75 rise=5 +meas tran c020l_n2r4 when v(n2_c020l)=0.75 rise=4 +meas tran c020l_n2f4 when v(n2_c020l)=0.75 fall=4 +meas tran c020l_n2f5 when v(n2_c020l)=0.75 fall=5 +meas tran c020l_ckf4 when v(ck_c020l)=0.75 fall=4 +meas tran c020l_ckr5 when v(ck_c020l)=0.75 rise=5 +meas tran c023l_n1f4 when v(n1_c023l)=0.75 fall=4 +meas tran c023l_n1r4 when v(n1_c023l)=0.75 rise=4 +meas tran c023l_n1r5 when v(n1_c023l)=0.75 rise=5 +meas tran c023l_n2r4 when v(n2_c023l)=0.75 rise=4 +meas tran c023l_n2f4 when v(n2_c023l)=0.75 fall=4 +meas tran c023l_n2f5 when v(n2_c023l)=0.75 fall=5 +meas tran c023l_ckf4 when v(ck_c023l)=0.75 fall=4 +meas tran c023l_ckr5 when v(ck_c023l)=0.75 rise=5 +meas tran c027l_n1f4 when v(n1_c027l)=0.75 fall=4 +meas tran c027l_n1r4 when v(n1_c027l)=0.75 rise=4 +meas tran c027l_n1r5 when v(n1_c027l)=0.75 rise=5 +meas tran c027l_n2r4 when v(n2_c027l)=0.75 rise=4 +meas tran c027l_n2f4 when v(n2_c027l)=0.75 fall=4 +meas tran c027l_n2f5 when v(n2_c027l)=0.75 fall=5 +meas tran c027l_ckf4 when v(ck_c027l)=0.75 fall=4 +meas tran c027l_ckr5 when v(ck_c027l)=0.75 rise=5 +meas tran c032l_n1f4 when v(n1_c032l)=0.75 fall=4 +meas tran c032l_n1r4 when v(n1_c032l)=0.75 rise=4 +meas tran c032l_n1r5 when v(n1_c032l)=0.75 rise=5 +meas tran c032l_n2r4 when v(n2_c032l)=0.75 rise=4 +meas tran c032l_n2f4 when v(n2_c032l)=0.75 fall=4 +meas tran c032l_n2f5 when v(n2_c032l)=0.75 fall=5 +meas tran c032l_ckf4 when v(ck_c032l)=0.75 fall=4 +meas tran c032l_ckr5 when v(ck_c032l)=0.75 rise=5 +meas tran c040l_n1f4 when v(n1_c040l)=0.75 fall=4 +meas tran c040l_n1r4 when v(n1_c040l)=0.75 rise=4 +meas tran c040l_n1r5 when v(n1_c040l)=0.75 rise=5 +meas tran c040l_n2r4 when v(n2_c040l)=0.75 rise=4 +meas tran c040l_n2f4 when v(n2_c040l)=0.75 fall=4 +meas tran c040l_n2f5 when v(n2_c040l)=0.75 fall=5 +meas tran c040l_ckf4 when v(ck_c040l)=0.75 fall=4 +meas tran c040l_ckr5 when v(ck_c040l)=0.75 rise=5 +meas tran c055l_n1f4 when v(n1_c055l)=0.75 fall=4 +meas tran c055l_n1r4 when v(n1_c055l)=0.75 rise=4 +meas tran c055l_n1r5 when v(n1_c055l)=0.75 rise=5 +meas tran c055l_n2r4 when v(n2_c055l)=0.75 rise=4 +meas tran c055l_n2f4 when v(n2_c055l)=0.75 fall=4 +meas tran c055l_n2f5 when v(n2_c055l)=0.75 fall=5 +meas tran c055l_ckf4 when v(ck_c055l)=0.75 fall=4 +meas tran c055l_ckr5 when v(ck_c055l)=0.75 rise=5 +meas tran c080l_n1f4 when v(n1_c080l)=0.75 fall=4 +meas tran c080l_n1r4 when v(n1_c080l)=0.75 rise=4 +meas tran c080l_n1r5 when v(n1_c080l)=0.75 rise=5 +meas tran c080l_n2r4 when v(n2_c080l)=0.75 rise=4 +meas tran c080l_n2f4 when v(n2_c080l)=0.75 fall=4 +meas tran c080l_n2f5 when v(n2_c080l)=0.75 fall=5 +meas tran c080l_ckf4 when v(ck_c080l)=0.75 fall=4 +meas tran c080l_ckr5 when v(ck_c080l)=0.75 rise=5 +meas tran c120l_n1f4 when v(n1_c120l)=0.75 fall=4 +meas tran c120l_n1r4 when v(n1_c120l)=0.75 rise=4 +meas tran c120l_n1r5 when v(n1_c120l)=0.75 rise=5 +meas tran c120l_n2r4 when v(n2_c120l)=0.75 rise=4 +meas tran c120l_n2f4 when v(n2_c120l)=0.75 fall=4 +meas tran c120l_n2f5 when v(n2_c120l)=0.75 fall=5 +meas tran c120l_ckf4 when v(ck_c120l)=0.75 fall=4 +meas tran c120l_ckr5 when v(ck_c120l)=0.75 rise=5 +meas tran c014h_n1f4 when v(n1_c014h)=0.75 fall=4 +meas tran c014h_n1r4 when v(n1_c014h)=0.75 rise=4 +meas tran c014h_n1r5 when v(n1_c014h)=0.75 rise=5 +meas tran c014h_n2r4 when v(n2_c014h)=0.75 rise=4 +meas tran c014h_n2f4 when v(n2_c014h)=0.75 fall=4 +meas tran c014h_n2f5 when v(n2_c014h)=0.75 fall=5 +meas tran c014h_ckf4 when v(ck_c014h)=0.75 fall=4 +meas tran c014h_ckr5 when v(ck_c014h)=0.75 rise=5 +meas tran c016h_n1f4 when v(n1_c016h)=0.75 fall=4 +meas tran c016h_n1r4 when v(n1_c016h)=0.75 rise=4 +meas tran c016h_n1r5 when v(n1_c016h)=0.75 rise=5 +meas tran c016h_n2r4 when v(n2_c016h)=0.75 rise=4 +meas tran c016h_n2f4 when v(n2_c016h)=0.75 fall=4 +meas tran c016h_n2f5 when v(n2_c016h)=0.75 fall=5 +meas tran c016h_ckf4 when v(ck_c016h)=0.75 fall=4 +meas tran c016h_ckr5 when v(ck_c016h)=0.75 rise=5 +meas tran c018h_n1f4 when v(n1_c018h)=0.75 fall=4 +meas tran c018h_n1r4 when v(n1_c018h)=0.75 rise=4 +meas tran c018h_n1r5 when v(n1_c018h)=0.75 rise=5 +meas tran c018h_n2r4 when v(n2_c018h)=0.75 rise=4 +meas tran c018h_n2f4 when v(n2_c018h)=0.75 fall=4 +meas tran c018h_n2f5 when v(n2_c018h)=0.75 fall=5 +meas tran c018h_ckf4 when v(ck_c018h)=0.75 fall=4 +meas tran c018h_ckr5 when v(ck_c018h)=0.75 rise=5 +meas tran c020h_n1f4 when v(n1_c020h)=0.75 fall=4 +meas tran c020h_n1r4 when v(n1_c020h)=0.75 rise=4 +meas tran c020h_n1r5 when v(n1_c020h)=0.75 rise=5 +meas tran c020h_n2r4 when v(n2_c020h)=0.75 rise=4 +meas tran c020h_n2f4 when v(n2_c020h)=0.75 fall=4 +meas tran c020h_n2f5 when v(n2_c020h)=0.75 fall=5 +meas tran c020h_ckf4 when v(ck_c020h)=0.75 fall=4 +meas tran c020h_ckr5 when v(ck_c020h)=0.75 rise=5 +meas tran c023h_n1f4 when v(n1_c023h)=0.75 fall=4 +meas tran c023h_n1r4 when v(n1_c023h)=0.75 rise=4 +meas tran c023h_n1r5 when v(n1_c023h)=0.75 rise=5 +meas tran c023h_n2r4 when v(n2_c023h)=0.75 rise=4 +meas tran c023h_n2f4 when v(n2_c023h)=0.75 fall=4 +meas tran c023h_n2f5 when v(n2_c023h)=0.75 fall=5 +meas tran c023h_ckf4 when v(ck_c023h)=0.75 fall=4 +meas tran c023h_ckr5 when v(ck_c023h)=0.75 rise=5 +meas tran c027h_n1f4 when v(n1_c027h)=0.75 fall=4 +meas tran c027h_n1r4 when v(n1_c027h)=0.75 rise=4 +meas tran c027h_n1r5 when v(n1_c027h)=0.75 rise=5 +meas tran c027h_n2r4 when v(n2_c027h)=0.75 rise=4 +meas tran c027h_n2f4 when v(n2_c027h)=0.75 fall=4 +meas tran c027h_n2f5 when v(n2_c027h)=0.75 fall=5 +meas tran c027h_ckf4 when v(ck_c027h)=0.75 fall=4 +meas tran c027h_ckr5 when v(ck_c027h)=0.75 rise=5 +meas tran c032h_n1f4 when v(n1_c032h)=0.75 fall=4 +meas tran c032h_n1r4 when v(n1_c032h)=0.75 rise=4 +meas tran c032h_n1r5 when v(n1_c032h)=0.75 rise=5 +meas tran c032h_n2r4 when v(n2_c032h)=0.75 rise=4 +meas tran c032h_n2f4 when v(n2_c032h)=0.75 fall=4 +meas tran c032h_n2f5 when v(n2_c032h)=0.75 fall=5 +meas tran c032h_ckf4 when v(ck_c032h)=0.75 fall=4 +meas tran c032h_ckr5 when v(ck_c032h)=0.75 rise=5 +meas tran c040h_n1f4 when v(n1_c040h)=0.75 fall=4 +meas tran c040h_n1r4 when v(n1_c040h)=0.75 rise=4 +meas tran c040h_n1r5 when v(n1_c040h)=0.75 rise=5 +meas tran c040h_n2r4 when v(n2_c040h)=0.75 rise=4 +meas tran c040h_n2f4 when v(n2_c040h)=0.75 fall=4 +meas tran c040h_n2f5 when v(n2_c040h)=0.75 fall=5 +meas tran c040h_ckf4 when v(ck_c040h)=0.75 fall=4 +meas tran c040h_ckr5 when v(ck_c040h)=0.75 rise=5 +meas tran c055h_n1f4 when v(n1_c055h)=0.75 fall=4 +meas tran c055h_n1r4 when v(n1_c055h)=0.75 rise=4 +meas tran c055h_n1r5 when v(n1_c055h)=0.75 rise=5 +meas tran c055h_n2r4 when v(n2_c055h)=0.75 rise=4 +meas tran c055h_n2f4 when v(n2_c055h)=0.75 fall=4 +meas tran c055h_n2f5 when v(n2_c055h)=0.75 fall=5 +meas tran c055h_ckf4 when v(ck_c055h)=0.75 fall=4 +meas tran c055h_ckr5 when v(ck_c055h)=0.75 rise=5 +meas tran c080h_n1f4 when v(n1_c080h)=0.75 fall=4 +meas tran c080h_n1r4 when v(n1_c080h)=0.75 rise=4 +meas tran c080h_n1r5 when v(n1_c080h)=0.75 rise=5 +meas tran c080h_n2r4 when v(n2_c080h)=0.75 rise=4 +meas tran c080h_n2f4 when v(n2_c080h)=0.75 fall=4 +meas tran c080h_n2f5 when v(n2_c080h)=0.75 fall=5 +meas tran c080h_ckf4 when v(ck_c080h)=0.75 fall=4 +meas tran c080h_ckr5 when v(ck_c080h)=0.75 rise=5 +meas tran c120h_n1f4 when v(n1_c120h)=0.75 fall=4 +meas tran c120h_n1r4 when v(n1_c120h)=0.75 rise=4 +meas tran c120h_n1r5 when v(n1_c120h)=0.75 rise=5 +meas tran c120h_n2r4 when v(n2_c120h)=0.75 rise=4 +meas tran c120h_n2f4 when v(n2_c120h)=0.75 fall=4 +meas tran c120h_n2f5 when v(n2_c120h)=0.75 fall=5 +meas tran c120h_ckf4 when v(ck_c120h)=0.75 fall=4 +meas tran c120h_ckr5 when v(ck_c120h)=0.75 rise=5 +meas tran h01_ckf1 when v(ck_h01)=0.75 fall=1 +meas tran h01_ckf2 when v(ck_h01)=0.75 fall=2 +meas tran h01_ckf3 when v(ck_h01)=0.75 fall=3 +meas tran h01_ckf4 when v(ck_h01)=0.75 fall=4 +meas tran h01_ckf5 when v(ck_h01)=0.75 fall=5 +meas tran h01_ckf6 when v(ck_h01)=0.75 fall=6 +meas tran h01_ckr2 when v(ck_h01)=0.75 rise=2 +meas tran h01_ckr3 when v(ck_h01)=0.75 rise=3 +meas tran h01_ckr4 when v(ck_h01)=0.75 rise=4 +meas tran h01_ckr5 when v(ck_h01)=0.75 rise=5 +meas tran h01_ckr6 when v(ck_h01)=0.75 rise=6 +meas tran h01_ckr7 when v(ck_h01)=0.75 rise=7 +meas tran h02_ckf1 when v(ck_h02)=0.75 fall=1 +meas tran h02_ckf2 when v(ck_h02)=0.75 fall=2 +meas tran h02_ckf3 when v(ck_h02)=0.75 fall=3 +meas tran h02_ckf4 when v(ck_h02)=0.75 fall=4 +meas tran h02_ckf5 when v(ck_h02)=0.75 fall=5 +meas tran h02_ckf6 when v(ck_h02)=0.75 fall=6 +meas tran h02_ckr2 when v(ck_h02)=0.75 rise=2 +meas tran h02_ckr3 when v(ck_h02)=0.75 rise=3 +meas tran h02_ckr4 when v(ck_h02)=0.75 rise=4 +meas tran h02_ckr5 when v(ck_h02)=0.75 rise=5 +meas tran h02_ckr6 when v(ck_h02)=0.75 rise=6 +meas tran h02_ckr7 when v(ck_h02)=0.75 rise=7 +meas tran h03_ckf1 when v(ck_h03)=0.75 fall=1 +meas tran h03_ckf2 when v(ck_h03)=0.75 fall=2 +meas tran h03_ckf3 when v(ck_h03)=0.75 fall=3 +meas tran h03_ckf4 when v(ck_h03)=0.75 fall=4 +meas tran h03_ckf5 when v(ck_h03)=0.75 fall=5 +meas tran h03_ckf6 when v(ck_h03)=0.75 fall=6 +meas tran h03_ckr2 when v(ck_h03)=0.75 rise=2 +meas tran h03_ckr3 when v(ck_h03)=0.75 rise=3 +meas tran h03_ckr4 when v(ck_h03)=0.75 rise=4 +meas tran h03_ckr5 when v(ck_h03)=0.75 rise=5 +meas tran h03_ckr6 when v(ck_h03)=0.75 rise=6 +meas tran h03_ckr7 when v(ck_h03)=0.75 rise=7 +meas tran h04_ckf1 when v(ck_h04)=0.75 fall=1 +meas tran h04_ckf2 when v(ck_h04)=0.75 fall=2 +meas tran h04_ckf3 when v(ck_h04)=0.75 fall=3 +meas tran h04_ckf4 when v(ck_h04)=0.75 fall=4 +meas tran h04_ckf5 when v(ck_h04)=0.75 fall=5 +meas tran h04_ckf6 when v(ck_h04)=0.75 fall=6 +meas tran h04_ckr2 when v(ck_h04)=0.75 rise=2 +meas tran h04_ckr3 when v(ck_h04)=0.75 rise=3 +meas tran h04_ckr4 when v(ck_h04)=0.75 rise=4 +meas tran h04_ckr5 when v(ck_h04)=0.75 rise=5 +meas tran h04_ckr6 when v(ck_h04)=0.75 rise=6 +meas tran h04_ckr7 when v(ck_h04)=0.75 rise=7 +meas tran h05_ckf1 when v(ck_h05)=0.75 fall=1 +meas tran h05_ckf2 when v(ck_h05)=0.75 fall=2 +meas tran h05_ckf3 when v(ck_h05)=0.75 fall=3 +meas tran h05_ckf4 when v(ck_h05)=0.75 fall=4 +meas tran h05_ckf5 when v(ck_h05)=0.75 fall=5 +meas tran h05_ckf6 when v(ck_h05)=0.75 fall=6 +meas tran h05_ckr2 when v(ck_h05)=0.75 rise=2 +meas tran h05_ckr3 when v(ck_h05)=0.75 rise=3 +meas tran h05_ckr4 when v(ck_h05)=0.75 rise=4 +meas tran h05_ckr5 when v(ck_h05)=0.75 rise=5 +meas tran h05_ckr6 when v(ck_h05)=0.75 rise=6 +meas tran h05_ckr7 when v(ck_h05)=0.75 rise=7 +meas tran h06_ckf1 when v(ck_h06)=0.75 fall=1 +meas tran h06_ckf2 when v(ck_h06)=0.75 fall=2 +meas tran h06_ckf3 when v(ck_h06)=0.75 fall=3 +meas tran h06_ckf4 when v(ck_h06)=0.75 fall=4 +meas tran h06_ckf5 when v(ck_h06)=0.75 fall=5 +meas tran h06_ckf6 when v(ck_h06)=0.75 fall=6 +meas tran h06_ckr2 when v(ck_h06)=0.75 rise=2 +meas tran h06_ckr3 when v(ck_h06)=0.75 rise=3 +meas tran h06_ckr4 when v(ck_h06)=0.75 rise=4 +meas tran h06_ckr5 when v(ck_h06)=0.75 rise=5 +meas tran h06_ckr6 when v(ck_h06)=0.75 rise=6 +meas tran h06_ckr7 when v(ck_h06)=0.75 rise=7 +meas tran h07_ckf1 when v(ck_h07)=0.75 fall=1 +meas tran h07_ckf2 when v(ck_h07)=0.75 fall=2 +meas tran h07_ckf3 when v(ck_h07)=0.75 fall=3 +meas tran h07_ckf4 when v(ck_h07)=0.75 fall=4 +meas tran h07_ckf5 when v(ck_h07)=0.75 fall=5 +meas tran h07_ckf6 when v(ck_h07)=0.75 fall=6 +meas tran h07_ckr2 when v(ck_h07)=0.75 rise=2 +meas tran h07_ckr3 when v(ck_h07)=0.75 rise=3 +meas tran h07_ckr4 when v(ck_h07)=0.75 rise=4 +meas tran h07_ckr5 when v(ck_h07)=0.75 rise=5 +meas tran h07_ckr6 when v(ck_h07)=0.75 rise=6 +meas tran h07_ckr7 when v(ck_h07)=0.75 rise=7 +meas tran k01_ckf10 when v(ck_k01)=0.75 fall=10 +meas tran k01_ckf11 when v(ck_k01)=0.75 fall=11 +meas tran k01_n1f11 when v(n1_k01)=0.75 fall=11 +meas tran k01_n2r11 when v(n2_k01)=0.75 rise=11 +.endc +.end diff --git a/specs/analog/decks/sar_gate_arcs.cir b/specs/analog/decks/sar_gate_arcs.cir index 4602e1f4ec..d232b57c85 100644 --- a/specs/analog/decks/sar_gate_arcs.cir +++ b/specs/analog/decks/sar_gate_arcs.cir @@ -5,7 +5,7 @@ SAR gate arcs: inverter, nor, nor3, nand and tgate delays of the golden SAR deck * for every input pin and both edges. From the three loads the spec fits delay = d0 + k * FO (fanout). * Paths are NOT in this file: ngspice reads IHP_PDK (the IHP-Open-PDK checkout), IHP_OSDI (the directory with the compiled psp103.osdi * and psp103_nqs.osdi) and SAR_GOLDEN_SUBCKTS (the subcircuit section of the golden deck, made at run time: -* sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^.(end|global)' > $SAR_GOLDEN_SUBCKTS ) from the environment. +* sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^\.(end|global)([[:space:]]|$)' > $SAR_GOLDEN_SUBCKTS ) from the environment. * Run: IHP_PDK= IHP_OSDI= SAR_GOLDEN_SUBCKTS= ngspice -b sar_gate_arcs.cir (ngspice-47) * It prints one line per arc: = . Names: d____ with r|f the OUTPUT edge; tgate: d_tgp (pass), d_tge (enable). * Model, corner and temperature: sg13_lv devices, mos_tt, 50 C (the golden deck says .options TEMP = 50). Edges: 0.2 ns, 10 ns apart from 40 ns. diff --git a/specs/analog/decks/sar_logic_ref.cir b/specs/analog/decks/sar_logic_ref.cir index a31a9ba792..72ae3bf2e0 100644 --- a/specs/analog/decks/sar_logic_ref.cir +++ b/specs/analog/decks/sar_logic_ref.cir @@ -7,7 +7,7 @@ SAR_logic and clock_gen of the golden SAR deck at transistor level, PSP103 tt at * them), so the CK edges below are the sequencer's own. Everything but the two ideal sources is the deck's own subcircuits. * Paths are NOT in this file: ngspice reads IHP_PDK (the IHP-Open-PDK checkout), IHP_OSDI (the directory with the compiled psp103.osdi and * psp103_nqs.osdi) and SAR_GOLDEN_SUBCKTS (the subcircuit section of the golden deck, made at run time: -* sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^.(end|global)' > $SAR_GOLDEN_SUBCKTS ) from the environment. +* sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^\.(end|global)([[:space:]]|$)' > $SAR_GOLDEN_SUBCKTS ) from the environment. * Run: IHP_PDK= IHP_OSDI= SAR_GOLDEN_SUBCKTS= ngspice -b sar_logic_ref.cir (ngspice-47) * Stimulus: clks is high from 0.5 ns to 31.5 ns (the reset, 50 % points) and low after; Valid rises (50 %) at 80.1 ns and every 40 ns after, * eleven pulses, 20 ns wide, falling (50 %) at 100.3 ns and every 40 ns after, edges 0.2 ns. Eleven pulses are one SAR conversion: CK11 .. CK1 rise one diff --git a/specs/analog/sar_logic.t27 b/specs/analog/sar_logic.t27 index 38995a8f15..0b548718f9 100644 --- a/specs/analog/sar_logic.t27 +++ b/specs/analog/sar_logic.t27 @@ -26,7 +26,8 @@ // is scheduled one propagation delay later, and withdrawn if the inputs revert first (an INERTIAL delay: a glitch shorter than the delay is // swallowed). The delay of an arc is d0 + k * FO: the arc is (kind, the input pin that changed, the output edge), FO the load of the output net in // units of ONE INVERTER INPUT (1.8 um^2 of gate): the sum of the loads of the pins on the net (an inverter, nor, nand or nor3 input is 1, a tgate's -// PMOS gate 0.75, its NMOS gate 0.25, its in and out terminals 0.15 each) plus the capacitance the top puts there (4 fF = 0.3, 8 fF = 0.6). d0 and k +// PMOS gate 0.75, its NMOS gate 0.25, its in terminal SL_TG_IN_LOAD = 0.43, its out terminal 0.15) plus the capacitance the top puts there (4 fF = 0.3, +// 8 fF = 0.6). d0 and k // are MEASURED (specs/analog/decks/sar_gate_arcs.cir: every gate driving 1, 4 and 16 inverter inputs, ngspice-47, IHP SG13G2 PSP103, mos_tt, 50 C), // least squares over the three loads; SL_NG_ARC pins the measured points and a test holds the fit to them. Not modelled: the slope of the input edge. // - @@ -35,7 +36,9 @@ // (dynamic storage: this is how the master and the slave remember). Drive strengths: a gate's output is strong; a tgate with both devices on passes // a strong 0 or 1; with one device on it passes strongly what that device passes well (an NMOS a 0, a PMOS a 1) and WEAKLY the other. A strong driver // beats a weak one; two drivers of equal strength and different value, or an unknown, make X. The dff needs this: in the clock-skew window the -// slave's x3 (NMOS on first) pulls net3 low while the keeper x7 (its NMOS still on until nCLK falls) pushes a weak 1, and net3 must go low. A tgate +// slave's x3 (NMOS on first) pulls net3 low while the keeper x7 (its NMOS still on until nCLK falls) pushes a weak 1, and net3 must go low. But a node +// that held the weak value when the strong driver arrives STAYS until the weak driver lets go: that fight is why ngspice's net3 falls 28 ps after nCLK +// does (133 ps after Valid) and not 83 ps after Valid, as the tgate's arc alone says, and why the CK edges came out 47 ps (9 %) early without it. A tgate // is used In -> Out only in this circuit (checked by a test: every tgate In is driven by a gate or by an input). Not modelled: the threshold drop of // a weak level (a weak 1 is a 1), charge sharing, leakage (a stored node never decays). // - @@ -54,40 +57,64 @@ // The delay cell's INPUT is not a gate capacitance: its long channels make the nor3 slower than 1.8 um^2 per input would, so the nor3 sees SL_DC_LOAD_R // and SL_DC_LOAD_F inverter inputs for a rising and a falling edge, MEASURED from the same deck (the nor3's 7.43 ns and 2.71 ns at code 000), i.e. // calibrated, not derived. The nor3's other arcs and the delay table are then tested on different stimuli (Valid, the 8 codes). +// - HISTORY (M4d-b, #10848). Those are SETTLED delays, and in the self-timed loop nothing settles: the nor3 output n1 (the delay cell input, 3 pF of long +// gate) and the delay cell output n2 are still moving when the next Valid edge comes. When Valid rises for the second time ngspice has n1 at 1.05 V and +// n2 at 0.39 V, still falling (the first time: 1.35 V and 0.08 V), and n2 rises in 6.1 ns, not 10.5. THE STATE of an output is its AGE: the time since it +// last crossed the other way (the nodes are first-order, and their voltage is a function of that time; every edge's delay, read from ngspice, is a +// single-valued curve of it: sar_delay_hist.cir, 29 pulse-train chains). The delay of an edge is the settled delay scaled by a table of the age: +// SL_H_N1F (n1 falling, on a Valid rise, by the age of its last rise), SL_H_N2R (n2 rising, by the age of its last fall), SL_H_N2F (n2 falling, by its age +// since its last rise) and SL_H_N1R (n1 rising, by the age of n2's last rise: n2 still rising pulls n1 up through the Miller capacitance, 5.8 ns after a +// short high time against 7.2 ns). The age is ms[SL_TCH + g], the time gate g's output last went from one known value to the other; out of the unknown +// start it is a long rest. The ages are in the tables as MEASURED points (11 each, linear between, flat outside), not fitted constants. A second +// history term: with two inputs of the nor3 high (Valid and CK1, the last pulse) n1 is pulled down by two NMOS and n2 rises 0.81 times as late +// (SL_C2_PM, fitted at one point). The inverter after the delay cell sees a slow edge and takes ngspice's delay for it, by trim code (SL_IV_R, SL_IV_F). +// The history is measured at code 000 and scaled by the settled delay of the code: the other codes keep the shape of 000 (not checked). // - // THE REFERENCE. ngspice-47, IHP SG13G2 PSP103 (the lv models, mos_tt) at 50 C (the golden deck's own temperature), transistor level, the deck's subcircuits. // PSP103, not LEVEL=1, is the reference: the issue text says LEVEL=1, but the IHP models run here (M3b), they are what the golden deck itself uses and -// they are the better reference. Four decks in specs/analog/decks, each a bench of my own wired to the golden subcircuits: +// they are the better reference. Five decks in specs/analog/decks, each a bench of my own wired to the golden subcircuits: // - sar_gate_arcs.cir: every gate driving 1, 4 and 16 inverter inputs (and the inverter driving 4 .. 32 fF): SL_ARC, SL_NG_ARC, SL_EXT_*. // - sar_delay_cell.cir: nor3 -> delay_cell -> inverter for the eight trim codes: SL_DC_*, SL_NG_TOT_*. // - sar_logic_ref.cir: SAR_logic and clock_gen wired as the golden top wires them (D = VDD, Set = 0, A = B = C = 0, 4 fF on CK1, 8 fF on clkc, 12 fF on // Valid), ideal clks and eleven Valid pulses: the 50 % crossings SL_NG_TV .. SL_NG_TCF. // - sar_logic_swap.cir: the same with the fifth dff's Set and Reset exchanged: SL_NG_SW_*. +// - sar_delay_hist.cir: 29 chains nor3 -> delay_cell -> inverter on Valid pulse trains: 21 CALIBRATION chains (Wh = 30 ns with Wl = 16 .. 120 ns; Wl = 30 ns +// with Wh = 14 .. 120 ns) give SL_HIST, SL_NG_HC_*; 7 HELD-OUT chains (other spacings, none in the tables) give SL_NG_HH_*; one chain with CK1 up on the +// last pulse gives SL_C2_PM, SL_NG_K1_F. 3m38 with `option klu` and `set num_threads=8`. // The decks read the golden subcircuits at run time: IHP_PDK, IHP_OSDI and SAR_GOLDEN_SUBCKTS are environment variables (no path is committed). // SAR_GOLDEN_SUBCKTS is the subcircuit section of the fetched deck: -// sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^.(end|global)' > $SAR_GOLDEN_SUBCKTS +// sed -n '/^.subckt tracking_switch/,$p' top.spice | grep -v -i -E '^\.(end|global)([[:space:]]|$)' > $SAR_GOLDEN_SUBCKTS +// (the first version of this line, '^.(end|global)', also dropped every `.ends`, and ngspice stopped at "Mismatch of .subckt ... .ends statements") // - // WHAT A PASS SAYS (each is a test below). (1) The converter hands this file 113 gates in 100 nets (23 inverter, 44 nor, 1 nor3, 44 tgate, 1 delay_cell), // every tgate read In -> Out with a stored Out. (2) After the reset every CK is 0 and no net is X. (3) Eleven Valid pulses make CK11 .. CK1 rise ONCE // each, in that order, the same order as ngspice, and they stay up; each edge is within SL_CK_BOUND_PM permille and SL_CK_ABS_PS ps of ngspice's delay // from its Valid edge. (4) The gate arcs reproduce the 60 measured points of sar_gate_arcs.cir within SL_ARC_ABS_PS ps. (5) For each of the 8 trim // codes the model's clks -> clkc delay, rising and falling, is within SL_DC_BOUND_PM permille of ngspice (sar_delay_cell.cir). (6) clkc rises after -// clks falls and makes one rise and one fall per Valid pulse (eleven falls, ten more rises: CK1 holds the last back), the first rise and the first fall -// within SL_CLKC_BOUND_PM permille of ngspice, the later edges within SL_REPEAT_R_BOUND_PM (rises) and SL_REPEAT_F_BOUND_PM (falls, wide: see below). -// (7) NEGATIVE CONTROL: a dff with Set and Reset swapped fails the order check, and the model shows what ngspice shows: CK7 high from the reset, falling at -// the first Valid edge and rising at its turn, CK6 rising a stage early. (8) A node only a tgate drives holds its value when the tgate turns off; a pulse -// shorter than the gate's delay is swallowed. +// clks falls and makes one rise and one fall per Valid pulse (eleven falls, ten more rises: CK1 holds the last back), EVERY one of the 22 edges, the +// repeated ones included, within SL_CLKC_BOUND_PM permille (8 %) of ngspice's delay from the causing Valid edge: the repeated falls are within 1.8 % +// (the issue asked for 15 %), the rises within 0.6 %, and the eleventh fall (CK1 up as well) too. (7) NEGATIVE CONTROL: a dff with Set and Reset +// swapped fails the order check, and the model shows what ngspice shows: CK7 high from the reset, falling at the first Valid edge and rising at its turn, +// CK6 rising a stage early. (8) A node only a tgate drives holds its value when the tgate turns off; a pulse shorter than the gate's delay is +// swallowed. (9) THE HISTORY: the four tables rise with age and end at the settled delays; the 21 calibration chains of sar_delay_hist.cir are reproduced +// within SL_CAL_BOUND_PM (3 %, and not exactly: the clkc delay holds the inverter and the rest of the chain); the 7 HELD-OUT chains (pulse spacings the +// tables never saw: 15 / 15, 25 / 25, 18 / 22, 24 / 16, 30 / 20, 22 / 38 ns and the golden 20.2 / 19.8) are reproduced at every one of their 6 falls +// and 6 rises within SL_CLKC_BOUND_PM (worst 5.1 %, a second pulse; settled ones within 1.7 %); the last fall with CK1 up is earlier than the one before +// by about ngspice's 1.2 ns. (10) NEGATIVE CONTROL of the history: with the history switched off (ms[SL_HON] = 0, the stateless delay cell of the first +// M4d) the repeated falls of the golden pace are 83 to 90 % late and fail the check the remembering cell passes, and the 15 / 15 pace is off by 180 %. // - // WHAT IT DOES NOT SAY. Not a transistor-level model of the logic, and no speed claim: nothing here is compared with how long ngspice takes. The CK // edges are the sequencer's own: no CK net carries the DAC's load, and the comparator closes the loop with a Valid of its own, not an ideal one. THE CK -// EDGES COME OUT ABOUT 17 % EARLY (458 ps against 548 ps from the Valid edge; CK1 625 ps against 654 ps): the model has no contention slowdown in the -// skew window and no input-slope term, and the bound says so. A CK FALLING (negative control only) comes 22 % early. THE REPEATED clkc EDGES ARE NOT -// RIGHT: the delay cell is history dependent. When Valid rises for the second time ngspice has the delay cell's input at 1.05 V and its output still at -// 0.39 V, still falling (in the first cycle: 1.35 V and 0.08 V), and the output then rises in 6.1 ns, not the 10.5 ns of a settled input. A table of -// settled delays can not follow that: in the repeated cycles ngspice's falling edge comes 7.0 ns after Valid rises, the table says 13.2 ns, 83 to -// 127 % too late; the rising edges are 6 to 11 % late. SL_REPEAT_F_BOUND_PM says how wrong the model -// is allowed to be there, and the PR lists every error. A conversion needs the self-timed loop closed through the comparator; that is M4e. A weak level -// is not degraded and a stored node does not leak. The delay cell input load and the 4 fF and 8 fF equivalents are fitted, not derived (above). +// EDGES were 17 % early in the first M4d (458 ps against 548 ps from the Valid edge; CK1 625 against 654). TWO causes: the fight of the skew window +// (the keeper still pushing a weak 1 while the slave pulls net3 down: +47 ps, 505 ps) and the In terminal of a tgate, which the arc decks do not measure +// (+41 ps, 546 ps, within 1 %; CK1 672 ps, 3 % late). The second is ONE FITTED NUMBER (SL_TG_IN_LOAD) set so that these edges come out right, so +// CK11 .. CK2 (one delay in the model) are not an independent check; what stays unexplained is why the real In terminal is 0.43 and not the 0.15 of the +// first guess (4 um of diffusion, measured by nothing here), and the input-slope term is still absent. A CK FALLING (negative control only) comes 20 % +// early (426 ps against 535 ps): the weak 1 charges the node faster than the real tgate. What the pulse-train chains do NOT cover: pulses whose +// ages fall below the calibrated range (Wh below 14 ns or Wl below 16 ns: the tables are flat there, nothing in the deck measures it, and a scratch +// prototype of the same law was 17 % off on the first rise of a 12 / 28 ns train), trim codes other than 000 (the history of 000 is scaled), the +// closed loop (that is M4e), and any process corner but tt at 50 C. A weak level is not degraded and a stored node does not leak. The delay cell input load and the +// 4 fF and 8 fF equivalents are fitted, not derived (above). // ASCII only, English only. // phi^2 + 1/phi^2 = 3 | TRINITY @@ -150,10 +177,63 @@ pub const SL_NG_TOT_F : [8]usize = [13305, 13479, 13479, 13609, 13479, 13609, 13 pub const SL_DC_LOAD_R : usize = 33380; pub const SL_DC_LOAD_F : usize = 75700; +/// What the In terminal of a tgate puts on its net (thousandths of an inverter input): 4 um of diffusion (the 3 um PMOS and the 1 um NMOS), first guessed +/// as 0.15, which left the CK11 .. CK2 edges 8 % early once the skew-window fight was in; FITTED to those edges (all ten are one delay in the model), so +/// they are no independent check of it. CK1, whose net carries no tgate In, and the swapped-pins control, which shares the path, are the other checks. +pub const SL_TG_IN_LOAD : usize = 430; + /// The capacitance of the golden top on CK1 (4 fF) and clkc (8 fF), in thousandths of an inverter input: what the inverter's delay at that cap equals. pub const SL_EXT_4F : usize = 300; pub const SL_EXT_8F : usize = 600; +/// THE HISTORY OF THE DELAY CELL (sar_delay_hist.cir). Four tables of SL_H_N pairs (age, delay), ps, ages rising; flat outside. The AGE of an output is the +/// time since that output last crossed the other way. SL_H_N1F: the nor3 output (n1, the delay cell input) falling, on a Valid rise, against the age of its +/// last rise; SL_H_N2R: the delay cell output (n2) rising against its age since its last fall, read at the moment n1 crosses; SL_H_N1R: n1 rising, on a Valid +/// fall, against the age of n2's last rise (n2 still rising pulls n1 up through the Miller capacitance); SL_H_N2F: n2 falling against its age since its last +/// rise. The delay of n1 is from the Valid edge, that of n2 from the n1 crossing. Code 000, the golden top. MEASURED, not fitted: each point is one +/// calibration chain of sar_delay_hist.cir at its fourth pulse (Wh = 30 ns with Wl = 16 .. 120 ns for the first two tables; Wl = 30 ns with Wh = 14 .. 120 ns +/// for the last two), the age and the delay both read from ngspice's 50 % crossings; the first pair of N1F, N2R and N1R repeats the next one (below the +/// shortest calibrated age the table is flat, which is an extrapolation). +pub const SL_H_N : usize = 11; +pub const SL_H_N1F : usize = 0; +pub const SL_H_N2R : usize = 22; +pub const SL_H_N1R : usize = 44; +pub const SL_H_N2F : usize = 66; +pub const SL_HIST : [88]usize = [ + 0, 590, 8840, 590, 10841, 662, 12843, 729, 15848, 840, 19857, 1010, 24869, 1241, 32887, 1600, 47913, 2156, 72934, 2675, 112943, 2887, + 0, 3944, 1817, 3944, 3928, 5066, 6034, 5938, 9194, 6943, 13419, 7914, 18706, 8745, 27131, 9557, 42764, 10227, 68336, 10491, 108568, 10551, + 0, 5775, 3978, 5775, 6088, 6195, 8168, 6485, 10230, 6694, 13299, 6913, 17364, 7080, 22419, 7153, 45529, 7183, 70563, 7294, 110578, 7352, + 9753, 6520, 12283, 6723, 14653, 6871, 16924, 6989, 20212, 7130, 24444, 7295, 29572, 7501, 37627, 7781, 52712, 8014, 77857, 8067, 117930, 8081 +]; +/// The age of a net that has not changed since the start (every net starts unknown, and the first change from unknown is the circuit at rest): a long rest. +pub const SL_AGE_INF : usize = 1000000; +/// The ages at which sar_delay_cell.cir measured the settled delays (clks low for 80 ns, high for 80 ns): the nor3 fall and the delay cell rise. +/// The settled numbers (SL_DC_*, SL_DC_LOAD_*) hold there; the tables above scale them for any other age. +pub const SL_H_REF_N1F : usize = 72800; +pub const SL_H_REF_N2R : usize = 67400; +/// The inverter after the delay cell sees a slow edge, so its delay is longer than its fast-edge arc: ps, measured as iv__r (clkc rising, by trim +/// code) and iv_0_f (clkc falling, the same for every code to 3 ps) in sar_delay_cell.cir. +pub const SL_IV_R : [8]usize = [626, 466, 466, 436, 466, 436, 436, 657]; +pub const SL_IV_F : usize = 114; +/// The delay cell's output rise when two inputs of its nor3 are high (Valid and CK1 on the last pulse), in thousandths of the rise with one: chain k01 of +/// sar_delay_hist.cir, 4905 ps from the n1 crossing, over the 6083 ps of SL_H_N2R at the same age. FITTED at one pace and one age. +pub const SL_C2_PM : usize = 806; + +/// ngspice's clkc delays in the chains of sar_delay_hist.cir, ps. The 21 calibration chains at their fourth pulse: the fall from Valid's rise, the rise from +/// Valid's fall. The 7 held-out chains (h01 .. h07) at all six pulses: SL_NG_HH_F[6 c + p] is the fall from Valid rise p, SL_NG_HH_R[6 c + p] the rise from +/// Valid fall p. Chain k01 (the golden pace, CK1 up with the eleventh edge): the falls from the tenth and the eleventh Valid rise. +pub const SL_NG_HC_F : [21]usize = [4648, 5843, 6782, 7899, 9040, 10102, 11272, 12498, 13282, 13554, 10138, 10027, 9947, 9885, 9816, 9752, 9696, 9640, 9586, 9552, 9538]; +pub const SL_NG_HC_R : [21]usize = [15399, 15360, 15322, 15272, 15217, 15162, 15096, 15019, 14965, 14946, 12923, 13545, 13983, 14310, 14670, 15002, 15281, 15559, 15823, 15987, 16059]; +pub const SL_NG_HH_F : [42]usize = [ + 12006, 7214, 6969, 6959, 6959, 6959, 12006, 5701, 4774, 4698, 4692, 4692, 12006, 8669, 8593, 8592, 8592, 8592, 12006, 8119, 7891, 7882, 7880, 7880, + 12006, 5182, 4844, 4834, 4833, 4833, 12006, 6891, 6784, 6782, 6782, 6782, 12006, 11128, 11113, 11113, 11113, 11113 +]; +pub const SL_NG_HH_R : [42]usize = [ + 14008, 14651, 14676, 14677, 14677, 14677, 12587, 14193, 14311, 14319, 14320, 14320, 14651, 14938, 14943, 14943, 14943, 14943, 13550, 14278, 14310, 14311, + 14311, 14311, 14545, 15099, 15116, 15116, 15116, 15116, 15050, 15317, 15321, 15322, 15322, 15321, 14293, 14411, 14413, 14413, 14412, 14413 +]; +pub const SL_NG_K1_F : [2]usize = [6958, 5741]; + /// ngspice's crossings (sar_logic_ref.cir), ps: Valid rising and falling (eleven pulses), clks falling, CK11 .. CK1 rising, clkc rising and falling. pub const SL_NG_TV : [11]usize = [80100, 120100, 160100, 200100, 240100, 280100, 320100, 360100, 400100, 440100, 480100]; pub const SL_NG_TVF : [11]usize = [100300, 140300, 180300, 220300, 260300, 300300, 340300, 380300, 420300, 460300, 500300]; @@ -170,20 +250,20 @@ pub const SL_NG_SW_CK6_R1 : usize = 80648; pub const SL_NG_SW_CK6_F : usize = 120635; pub const SL_NG_SW_CK6_R2 : usize = 280648; -/// The bounds the tests hold the model to. CK edges: permille of ngspice's Valid -> CK delay. Arcs: ps. The delay cell: permille of the end-to-end -/// delay. clkc, the first (settled) edges: permille; the repeated edges: permille of ngspice's delay from the causing Valid edge (wide, the model is -/// wrong there and says so). -pub const SL_CK_BOUND_PM : usize = 200; -pub const SL_CK_ABS_PS : usize = 100; +/// The bounds the tests hold the model to. CK edges: permille of ngspice's Valid -> CK delay (the model is within 1 %, CK1 3 % late). Arcs: ps. The delay +/// cell: permille of the end-to-end delay, settled. clkc, in the sequencer run and in the pulse-train chains (first and repeated edges alike): permille of +/// ngspice's delay from the causing Valid edge, the issue's 15 % cut to 8 % (the worst edge is 5.1 %, a second pulse; the settled ones are within 1.7 %). +/// SL_CAL_BOUND_PM: the calibration chains, whose points are in the tables. +pub const SL_CK_BOUND_PM : usize = 50; +pub const SL_CK_ABS_PS : usize = 30; /// A CK FALLING (only in the negative control: a stage takes a 0): the model's weak 1 charges the node faster than the NMOS of the real tgate, so the /// fall comes about 22 % early, and the bound is wider. pub const SL_FALL_BOUND_PM : usize = 250; pub const SL_FALL_ABS_PS : usize = 150; pub const SL_ARC_ABS_PS : usize = 25; pub const SL_DC_BOUND_PM : usize = 60; -pub const SL_CLKC_BOUND_PM : usize = 150; -pub const SL_REPEAT_R_BOUND_PM : usize = 150; -pub const SL_REPEAT_F_BOUND_PM : usize = 1300; +pub const SL_CLKC_BOUND_PM : usize = 80; +pub const SL_CAL_BOUND_PM : usize = 30; /// Changes before this time (ps) are the reset settling from unknown, not edges of the run. pub const SL_TMIN : usize = 20000; @@ -192,7 +272,7 @@ pub const SL_TMIN : usize = 20000; /// Capacities, and where each table sits in the state vector `ms` (zeroed by the caller, SL_SLOTS long). pub const SL_NETS : usize = 128; pub const SL_GATES : usize = 160; -pub const SL_SLOTS : usize = 5000; +pub const SL_SLOTS : usize = 5500; pub const SL_VAL : usize = 0; pub const SL_CNT : usize = 128; pub const SL_EXT : usize = 896; @@ -211,6 +291,12 @@ pub const SL_LOG : usize = 2900; pub const SL_LOGMAX : usize = 640; pub const SL_SI : usize = 4825; pub const SL_EXTL : usize = 4830; +/// The time each gate's output last changed from one known value to the other (NONE: never, or only out of the unknown start); the delay cell a gate +/// drives (that gate + 1, 0: none); the delay cell an inverter is fed by (that gate + 1, 0: none); the switch of the history (1: on, 0: the old, stateless cell). +pub const SL_TCH : usize = 4960; +pub const SL_CELL : usize = 5120; +pub const SL_FED : usize = 5280; +pub const SL_HON : usize = 5440; pub const SL_MAXSTEP : usize = 200000; /// The kind of gate g, and its pin p (a net), in the converter's table. @@ -252,7 +338,8 @@ pub fn sl_pin_load(kind: usize, p: usize, dir: usize) -> usize { if (kind == G_TGATE) { if (p == 0) { return 750; } if (p == 1) { return 250; } - if (p == 2 or p == 3) { return 150; } + if (p == 2) { return SL_TG_IN_LOAD; } + if (p == 3) { return 150; } return 0; } if (p == 0) { @@ -367,8 +454,53 @@ pub fn sl_trigger(ms: []const usize, gt: []const usize, g: usize) -> usize { return hit; } -/// The propagation delay, ps, of gate g changing to `want`: an unknown or a release is 1 ps; a delay cell reads its table; the others d0 + k * FO. -pub fn sl_delay(ms: []const usize, gt: []const usize, g: usize, ask: usize) -> usize { +/// The delay of the age `age` in the history table at `tab` (SL_H_N pairs of age and delay in SL_HIST), by linear interpolation; flat outside. +pub fn sl_h_get(tab: usize, age: usize) -> usize { + if (age <= SL_HIST[tab]) { return SL_HIST[tab + 1]; } + var i : usize = 1; + var d : usize = SL_HIST[tab + 2 * (SL_H_N - 1) + 1]; + var found : bool = false; + while (i < SL_H_N and !found) { + const a1 : usize = SL_HIST[tab + 2 * i]; + if (age <= a1) { + const a0 : usize = SL_HIST[tab + 2 * (i - 1)]; + const d0 : usize = SL_HIST[tab + 2 * (i - 1) + 1]; + const d1 : usize = SL_HIST[tab + 2 * i + 1]; + d = d0 + (d1 - d0) * (age - a0) / (a1 - a0); + found = true; + } + i = i + 1; + } + return d; +} + +/// How long ago gate g's output last changed from one known value to the other, ps; SL_AGE_INF when it never did. +pub fn sl_age(ms: []const usize, g: usize, t: usize) -> usize { + const c : usize = ms[SL_TCH + g]; + if (c == NONE or c > t) { return SL_AGE_INF; } + return t - c; +} + +/// How many input pins of gate g are at 1. +pub fn sl_high_in(ms: []const usize, gt: []const usize, g: usize) -> usize { + var c : usize = 0; + var j : usize = 0; + while (j < sl_n_in(sl_kind(gt, g))) { + if (ms[SL_VAL + sl_pin(gt, g, j)] == 1) { c = c + 1; } + j = j + 1; + } + return c; +} + +/// `base`, the settled delay of an edge, scaled to the age of the output: the table's delay at `age` over its delay at `ref_age` (where `base` was measured). +pub fn sl_h_scale(base: usize, tab: usize, age: usize, ref_age: usize) -> usize { + return base * sl_h_get(tab, age) / sl_h_get(tab, ref_age); +} + +/// The propagation delay, ps, of gate g changing to `ask` at time t: an unknown or a release is 1 ps; a delay cell reads its table and the age of +/// its output; the nor3 that drives a delay cell scales d0 + k * FO to the age of its output (a fall) or of the cell's output (a rise); the inverter the +/// cell drives takes the measured delay of a slow edge; the others d0 + k * FO. +pub fn sl_delay(ms: []const usize, gt: []const usize, g: usize, ask: usize, t: usize) -> usize { var dir : usize = SL_FALL; var known : bool = false; if (ask == SL_S1 or ask == SL_W1) { @@ -384,16 +516,48 @@ pub fn sl_delay(ms: []const usize, gt: []const usize, g: usize, ask: usize) -> u if ((cur == SL_S1 or cur == SL_W1) and (ask == SL_S1 or ask == SL_W1)) { return 1; } if ((cur == SL_S0 or cur == SL_W0) and (ask == SL_S0 or ask == SL_W0)) { return 1; } } + const hist : bool = ms[SL_HON] == 1; if (kind == G_DELAY) { const c : usize = sl_code(ms, gt, g); - if (dir == SL_RISE) { return SL_DC_RISE[c]; } + if (dir == SL_RISE) { + if (hist) { + var r : usize = sl_h_scale(SL_DC_RISE[c], SL_H_N2R, sl_age(ms, g, t), SL_H_REF_N2R); + // two inputs of the nor3 high (Valid and CK1 at the end of a conversion): two NMOS pull its output down, it reaches 0 sooner and the + // delay cell's PMOS charges its output sooner + const drv : usize = ms[SL_FED + g]; + if (drv != 0 and sl_high_in(ms, gt, drv - 1) >= 2) { r = r * SL_C2_PM / 1000; } + return r; + } + return SL_DC_RISE[c]; + } + if (hist) { return sl_h_scale(SL_DC_FALL[c], SL_H_N2F, sl_age(ms, g, t), SL_AGE_INF); } return SL_DC_FALL[c]; } const net : usize = sl_out_net(gt, g); var load : usize = ms[SL_LDF + net]; if (dir == SL_RISE) { load = ms[SL_LDR + net]; } if (kind == G_TGATE) { load = load - 150; } - const d : usize = sl_arc(sl_row(kind, sl_trigger(ms, gt, g)), dir, load); + var d : usize = sl_arc(sl_row(kind, sl_trigger(ms, gt, g)), dir, load); + const cell : usize = ms[SL_CELL + g]; + if (hist and cell != 0) { + if (dir == SL_FALL) { + d = sl_h_scale(d, SL_H_N1F, sl_age(ms, g, t), SL_H_REF_N1F); + } else { + // the cell's output still rising pulls this net up: its age since its last rise; a cell that is low has no such help + var a2 : usize = SL_AGE_INF; + if (ms[SL_DRV + cell - 1] == SL_S1) { a2 = sl_age(ms, cell - 1, t); } + d = sl_h_scale(d, SL_H_N1R, a2, SL_AGE_INF); + } + } + const fed : usize = ms[SL_FED + g]; + if (fed != 0) { + // the cell's output edge is slow: the inverter's delay is what sar_delay_cell.cir measured for that trim code, at its 8 fF + if (dir == SL_RISE) { + d = d + SL_IV_R[sl_code(ms, gt, fed - 1)] - sl_arc(0, SL_RISE, SL_EXT_8F); + } else { + d = d + SL_IV_F - sl_arc(0, SL_FALL, SL_EXT_8F); + } + } if (d < 1) { return 1; } return d; } @@ -416,8 +580,9 @@ pub fn sl_net(w: []const u8, gt: []const usize, name: []const u8) -> usize { return NONE; } -/// The model at t = 0: every net unknown, every gate driving X, nothing pending, no input driven, nothing watched. +/// The model at t = 0: every net unknown, every gate driving X, nothing pending, no input driven, nothing watched, the history of the delay cell on. pub fn sl_init(ms: []usize, gt: []const usize) -> void { + ms[SL_HON] = 1; var n : usize = 0; while (n < gt[GT_NNET]) { ms[SL_VAL + n] = SL_X; @@ -427,6 +592,7 @@ pub fn sl_init(ms: []usize, gt: []const usize) -> void { while (g < gt[GT_NGATE]) { ms[SL_DRV + g] = SL_X; ms[SL_PT + g] = NONE; + ms[SL_TCH + g] = NONE; var j : usize = 0; while (j < 7) { ms[SL_PREV + g * 7 + j] = SL_X; @@ -436,8 +602,30 @@ pub fn sl_init(ms: []usize, gt: []const usize) -> void { } } +/// The links of the delay cell: for each gate, the delay cell its output feeds (SL_CELL); the delay cell that feeds an inverter, and the gate that drives +/// a delay cell (SL_FED). +pub fn sl_links(ms: []usize, gt: []const usize) -> void { + var g : usize = 0; + while (g < gt[GT_NGATE]) { + ms[SL_CELL + g] = 0; + ms[SL_FED + g] = 0; + var h : usize = 0; + while (h < gt[GT_NGATE]) { + if (sl_kind(gt, h) == G_DELAY) { + if (sl_kind(gt, g) != G_DELAY and sl_pin(gt, h, 0) == sl_out_net(gt, g)) { ms[SL_CELL + g] = h + 1; } + if (sl_kind(gt, g) == G_INV and sl_out_net(gt, h) == sl_pin(gt, g, 0)) { ms[SL_FED + g] = h + 1; } + } else if (sl_kind(gt, g) == G_DELAY and sl_out_net(gt, h) == sl_pin(gt, g, 0)) { + ms[SL_FED + g] = h + 1; + } + h = h + 1; + } + g = g + 1; + } +} + /// The loads of every net, from the pins on it and the capacitance the top added (SL_EXTL, set by sl_ext_load before this). pub fn sl_loads(ms: []usize, gt: []const usize) -> void { + sl_links(ms, gt); var n : usize = 0; while (n < gt[GT_NNET]) { ms[SL_LDR + n] = ms[SL_EXTL + n]; @@ -503,7 +691,13 @@ pub fn sl_resolve(ms: []const usize, n: usize, old: usize) -> usize { const w1 : usize = ms[b + SL_W1]; if (s0 + s1 + sx > 0) { if (sx > 0 or (s0 > 0 and s1 > 0)) { return SL_X; } - if (s1 > 0) { return 1; } + // a strong driver against a weak one that holds the node at the other value: the fight of the skew window (the slave's NMOS pulls a 1 down while + // the keeper's NMOS still pushes it up); the node stays until the weak driver lets go, as ngspice's does (+65 ps on the CK edge) + if (s1 > 0) { + if (w0 > 0 and old == 0) { return 0; } + return 1; + } + if (w1 > 0 and old == 1) { return 1; } return 0; } if (w0 + w1 > 0) { @@ -523,12 +717,12 @@ pub fn sl_sched(ms: []usize, gt: []const usize, g: usize, t: usize) -> void { if (ask == cur) { ms[SL_PT + g] = NONE; } else { - ms[SL_PT + g] = t + sl_delay(ms, gt, g, ask); + ms[SL_PT + g] = t + sl_delay(ms, gt, g, ask, t); ms[SL_PV + g] = ask; } } } else if (ask != cur) { - ms[SL_PT + g] = t + sl_delay(ms, gt, g, ask); + ms[SL_PT + g] = t + sl_delay(ms, gt, g, ask, t); ms[SL_PV + g] = ask; } const kind : usize = sl_kind(gt, g); @@ -544,7 +738,12 @@ pub fn sl_step(ms: []usize, gt: []const usize, t: usize) -> void { var g : usize = 0; while (g < gt[GT_NGATE]) { if (ms[SL_PT + g] == t) { - ms[SL_DRV + g] = ms[SL_PV + g]; + const was : usize = ms[SL_DRV + g]; + const now : usize = ms[SL_PV + g]; + // the age of an output counts from a change between the two known values; out of the unknown start it counts as a long rest + if ((was == SL_S0 or was == SL_S1) and (now == SL_S0 or now == SL_S1) and was != now) { ms[SL_TCH + g] = t; } + if (was == SL_X) { ms[SL_TCH + g] = NONE; } + ms[SL_DRV + g] = now; ms[SL_PT + g] = NONE; } g = g + 1; @@ -789,6 +988,112 @@ pub fn sl_order_ok(ms: []const usize, ids: []const usize) -> bool { return true; } +// ---------------------------------------------------------------- the pulse-train chains of sar_delay_hist.cir + +/// The first fall of Valid and the first rise, ps, in every chain of sar_delay_hist.cir (the golden run's clks fall, then 48.6 ns of waiting). +pub const SL_H_FALL0 : usize = 1100; +pub const SL_H_T0 : usize = 49700; +/// The model starts from unknown, ngspice from the circuit at rest: the model rests this long (Valid high) before the deck's time zero, so the gates leave +/// the unknown and the first real edges are measured from rest. Every time below is the deck's plus this. +pub const SL_H_REST : usize = 50000; + +/// The calibration chains, in the order of the deck: Wh = 30 ns with Wl = 16 .. 120 ns, then Wl = 30 ns with Wh = 14 .. 120 ns (ps; four pulses each). +pub const SL_HC_WH : [21]usize = [30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 14000, 16000, 18000, 20000, 23000, 27000, 32000, 40000, 55000, 80000, 120000]; +pub const SL_HC_WL : [21]usize = [16000, 18000, 20000, 23000, 27000, 32000, 40000, 55000, 80000, 120000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000]; +/// The held-out chains h01 .. h07 (six pulses each; h01 is the golden pace). +pub const SL_HH_WH : [7]usize = [20200, 15000, 25000, 18000, 24000, 30000, 22000]; +pub const SL_HH_WL : [7]usize = [19800, 15000, 25000, 22000, 16000, 20000, 38000]; +pub const SL_HH_N : usize = 6; + +/// The nets of the clock_gen chain that the pulse-train runs use, in `ids`: vdd, vss, clks, valid, ck1, a, b, c, clkc. +pub fn sl_chain_ids(w: []const u8, gt: []const usize, ids: []usize) -> void { + ids[0] = sl_net(w, gt, "vdd"); + ids[1] = sl_net(w, gt, "vss"); + ids[2] = sl_net(w, gt, "clks"); + ids[3] = sl_net(w, gt, "valid"); + ids[4] = sl_net(w, gt, "ck1"); + ids[5] = sl_net(w, gt, "a"); + ids[6] = sl_net(w, gt, "b"); + ids[7] = sl_net(w, gt, "c"); + ids[8] = sl_net(w, gt, "vout"); +} + +/// Read the netlist, build the model of `clock_gen` alone (the nor3, the delay cell and the inverter, 8 fF on clkc) and watch clkc. False when the +/// converter refuses the netlist. +pub fn sl_chain_build(src: []u8, w: []u8, out: []u8, st: []usize, gt: []usize, ms: []usize, ids: []usize) -> bool { + const len : usize = sl_deck(src, false); + const n : usize = emit_gates(src[0 .. len], "clock_gen", w, out, st, gt); + if (st[ERR_LINE] != 0 or n == 0) { return false; } + sl_init(ms, gt); + sl_chain_ids(w, gt, ids); + sl_ext_load(ms, ids[8], SL_EXT_8F); + sl_loads(ms, gt); + sl_watch(ms, ids[8]); + return true; +} + +/// The stimulus of one chain of sar_delay_hist.cir: Valid starts high (the circuit at rest), falls at SL_H_FALL0, then `npulse` pulses of high time wh and +/// low time wl from SL_H_T0 on (ps); with `ck1_last` CK1 rises 654 ps after the last Valid rise and stays up (chain k01). +pub fn sl_chain_stim(s_t: []usize, s_n: []usize, s_v: []usize, ids: []const usize, wh: usize, wl: usize, npulse: usize, ck1_last: bool) -> usize { + var k : usize = 0; + k = sl_put(s_t, s_n, s_v, k, 0, ids[0], 1); + k = sl_put(s_t, s_n, s_v, k, 0, ids[1], 0); + k = sl_put(s_t, s_n, s_v, k, 0, ids[2], 0); + k = sl_put(s_t, s_n, s_v, k, 0, ids[4], 0); + k = sl_put(s_t, s_n, s_v, k, 0, ids[5], 0); + k = sl_put(s_t, s_n, s_v, k, 0, ids[6], 0); + k = sl_put(s_t, s_n, s_v, k, 0, ids[7], 0); + k = sl_put(s_t, s_n, s_v, k, 0, ids[3], 1); + k = sl_put(s_t, s_n, s_v, k, SL_H_REST + SL_H_FALL0, ids[3], 0); + var p : usize = 0; + while (p < npulse) { + const t : usize = SL_H_REST + SL_H_T0 + p * (wh + wl); + k = sl_put(s_t, s_n, s_v, k, t, ids[3], 1); + if (ck1_last and p + 1 == npulse) { k = sl_put(s_t, s_n, s_v, k, t + 654, ids[4], 1); } + k = sl_put(s_t, s_n, s_v, k, t + wh, ids[3], 0); + p = p + 1; + } + return k; +} + +/// Run a chain of `npulse` pulses to its end: the model of clock_gen, the stimulus, 40 ns past the last Valid fall. False when the netlist is refused. +pub fn sl_chain_run(ms: []usize, ids: []usize, wh: usize, wl: usize, npulse: usize, ck1_last: bool, hist: bool) -> bool { + var src : [4096]u8 = undefined; + var w : [24576]u8 = undefined; + var out : [24576]u8 = undefined; + var st : [3000]usize = [0] ** 3000; + var gt : [3200]usize = [0] ** 3200; + if (!sl_chain_build(&src, &w, &out, &st, >, ms, ids)) { return false; } + if (!hist) { ms[SL_HON] = 0; } + var s_t : [64]usize = [0] ** 64; + var s_n : [64]usize = [0] ** 64; + var s_v : [64]usize = [0] ** 64; + const k : usize = sl_chain_stim(&s_t, &s_n, &s_v, ids, wh, wl, npulse, ck1_last); + sl_run(ms, >, &s_t, &s_n, &s_v, k, SL_H_REST + SL_H_T0 + npulse * (wh + wl) + 40000); + return true; +} + +/// Valid's rise number p (from 0) and fall number p, ps. +pub fn sl_chain_tr(wh: usize, wl: usize, p: usize) -> usize { + return SL_H_REST + SL_H_T0 + p * (wh + wl); +} + +/// The error, permille, of the model's clkc fall caused by Valid rise p (the delay from that edge) against ngspice's `ng` ps; 9999 when there is no such edge. +pub fn sl_chain_err_f(ms: []const usize, ids: []const usize, wh: usize, wl: usize, p: usize, ng: usize) -> usize { + const e : usize = sl_edge(ms, ids[8], 0, p + 1, SL_H_REST); + const tr : usize = sl_chain_tr(wh, wl, p); + if (e == NONE or e < tr) { return 9999; } + return sl_err_pm(e - tr, ng); +} + +/// The same for the clkc rise caused by Valid fall p (the rise number p + 2: the first rise is the start). +pub fn sl_chain_err_r(ms: []const usize, ids: []const usize, wh: usize, wl: usize, p: usize, ng: usize) -> usize { + const e : usize = sl_edge(ms, ids[8], 1, p + 2, SL_H_REST); + const tf : usize = sl_chain_tr(wh, wl, p) + wh; + if (e == NONE or e < tf) { return 9999; } + return sl_err_pm(e - tf, ng); +} + // ---------------------------------------------------------------- tests // Each test builds the model from the netlist text above: the converter reads it into `gt`, the model runs on `gt`. The buffers are the caller's. @@ -814,12 +1119,24 @@ test the_gate_logic_is_the_truth_table_of_each_kind { } test a_net_takes_the_stronger_driver_holds_when_nothing_drives_and_goes_unknown_on_a_tie { - var ms : [5000]usize = [0] ** 5000; - // net 0: a strong 0 and a weak 1 -> 0; a weak 1 alone -> 1; a strong 0 and a strong 1 -> X; nothing -> the old value + var ms : [5500]usize = [0] ** 5500; + // net 0: a strong 0 and a weak 1 -> 0, but a node that held the weak 1 stays at 1 until the weak driver lets go (the fight of the skew window); + // a weak 1 alone -> 1; a strong 0 and a strong 1 -> X; nothing -> the old value ms[SL_CNT + SL_S0] = 1; ms[SL_CNT + SL_W1] = 1; - assert(sl_resolve(&ms, 0, 1) == 0); + assert(sl_resolve(&ms, 0, 1) == 1); + assert(sl_resolve(&ms, 0, 0) == 0); + assert(sl_resolve(&ms, 0, SL_X) == 0); ms[SL_CNT + SL_S0] = 0; + ms[SL_CNT + SL_S1] = 1; + ms[SL_CNT + SL_W1] = 0; + ms[SL_CNT + SL_W0] = 1; + assert(sl_resolve(&ms, 0, 0) == 0); + assert(sl_resolve(&ms, 0, 1) == 1); + // the weak 1 alone + ms[SL_CNT + SL_S1] = 0; + ms[SL_CNT + SL_W0] = 0; + ms[SL_CNT + SL_W1] = 1; assert(sl_resolve(&ms, 0, 0) == 1); ms[SL_CNT + SL_W0] = 1; assert(sl_resolve(&ms, 0, 0) == SL_X); @@ -910,7 +1227,7 @@ test the_reset_resolves_the_unknown_start_and_clears_every_ck { var out : [24576]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; var ids : [24]usize = [0] ** 24; var s_t : [64]usize = [0] ** 64; var s_n : [64]usize = [0] ** 64; @@ -943,7 +1260,7 @@ test eleven_valid_pulses_make_ck11_to_ck1_rise_once_each_in_ngspices_order_withi var out : [24576]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; var ids : [24]usize = [0] ** 24; var s_t : [64]usize = [0] ** 64; var s_n : [64]usize = [0] ** 64; @@ -974,7 +1291,7 @@ test the_asynchronous_clock_starts_after_clks_falls_and_follows_every_valid_puls var out : [24576]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; var ids : [24]usize = [0] ** 24; var s_t : [64]usize = [0] ** 64; var s_n : [64]usize = [0] ** 64; @@ -992,15 +1309,16 @@ test the_asynchronous_clock_starts_after_clks_falls_and_follows_every_valid_puls const f1 : usize = sl_edge(&ms, ids[20], 0, 1, SL_TMIN); assert(f1 > SL_NG_TV[0]); assert(sl_err_pm(f1 - SL_NG_TV[0], SL_NG_TCF[0] - SL_NG_TV[0]) <= SL_CLKC_BOUND_PM); - // the repeated edges: each from the Valid edge that causes it, with the wide bounds of the header + // the repeated edges, the ten rises and the ten falls after the first: each from the Valid edge that causes it, within the same bound (the delay cell + // remembers its last edges); the eleventh fall is the one with CK1 up as well var i : usize = 1; while (i < 11) { const rr : usize = sl_edge(&ms, ids[20], 1, i + 1, SL_TMIN); assert(rr > SL_NG_TVF[i - 1]); - assert(sl_err_pm(rr - SL_NG_TVF[i - 1], SL_NG_TCR[i] - SL_NG_TVF[i - 1]) <= SL_REPEAT_R_BOUND_PM); + assert(sl_err_pm(rr - SL_NG_TVF[i - 1], SL_NG_TCR[i] - SL_NG_TVF[i - 1]) <= SL_CLKC_BOUND_PM); const ff : usize = sl_edge(&ms, ids[20], 0, i + 1, SL_TMIN); assert(ff > SL_NG_TV[i]); - assert(sl_err_pm(ff - SL_NG_TV[i], SL_NG_TCF[i] - SL_NG_TV[i]) <= SL_REPEAT_F_BOUND_PM); + assert(sl_err_pm(ff - SL_NG_TV[i], SL_NG_TCF[i] - SL_NG_TV[i]) <= SL_CLKC_BOUND_PM); i = i + 1; } } @@ -1044,7 +1362,7 @@ test the_delay_cell_trim_codes_give_ngspices_clks_to_clkc_delays_for_all_eight_s var out : [24576]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; const len : usize = sl_deck(&src, false); const n : usize = emit_gates(src[0 .. len], "clock_gen", &w, &out, &st, >); assert(n > 0); @@ -1097,7 +1415,7 @@ test a_node_that_only_a_tgate_drives_holds_its_value_when_the_tgate_turns_off { var out : [4096]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; // one tgate (PMOS gate en, NMOS gate nen) from d to q, and an inverter on q const len : usize = sl_cat(&src, 0, "hold\n.subckt inverter Vin VDD VSS Vout\n.ends\n.subckt tgate CLK nCLK In Out VDD VSS\n.ends\n.subckt hold en nen d q y vdd vss\nx1 en nen d q vdd vss tgate\nx2 q vdd vss y inverter\n.ends\n.end\n"); const n : usize = emit_gates(src[0 .. len], "hold", &w, &out, &st, >); @@ -1150,7 +1468,7 @@ test a_pulse_shorter_than_the_delay_is_swallowed_and_a_tie_of_two_drivers_is_unk var out : [4096]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; // an inverter y = not a, unloaded: its fall takes d0 = 64 ps, its rise 48 ps const len : usize = sl_cat(&src, 0, "glitch\n.subckt inverter Vin VDD VSS Vout\n.ends\n.subckt top a y vdd vss\nx1 a vdd vss y inverter\n.ends\n.end\n"); const n : usize = emit_gates(src[0 .. len], "top", &w, &out, &st, >); @@ -1184,7 +1502,7 @@ test one_dff_with_set_and_reset_swapped_fails_the_order_check_that_the_right_net var out : [24576]u8 = undefined; var st : [3000]usize = [0] ** 3000; var gt : [3200]usize = [0] ** 3200; - var ms : [5000]usize = [0] ** 5000; + var ms : [5500]usize = [0] ** 5500; var ids : [24]usize = [0] ** 24; var s_t : [64]usize = [0] ** 64; var s_n : [64]usize = [0] ** 64; @@ -1196,7 +1514,7 @@ test one_dff_with_set_and_reset_swapped_fails_the_order_check_that_the_right_net // the same run on the netlist whose fifth dff has Set = clks and Reset = Set var st2 : [3000]usize = [0] ** 3000; var gt2 : [3200]usize = [0] ** 3200; - var ms2 : [5000]usize = [0] ** 5000; + var ms2 : [5500]usize = [0] ** 5500; var ids2 : [24]usize = [0] ** 24; assert(sl_build(&src, &w, &out, &st2, >2, &ms2, &ids2, true)); k = sl_stim(&s_t, &s_n, &s_v, &ids2); @@ -1227,3 +1545,124 @@ test one_dff_with_set_and_reset_swapped_fails_the_order_check_that_the_right_net // the other stages are untouched: CK11 rises once, on time assert(sl_edges(&ms2, ids2[9], 1, 0) == 1); } + +test the_history_tables_rise_with_age_end_at_the_settled_delays_and_interpolate { + // each table: ages strictly rising, delays never falling + var t : usize = 0; + while (t < 4) { + const tab : usize = t * 2 * SL_H_N; + var i : usize = 1; + while (i < SL_H_N) { + assert(SL_HIST[tab + 2 * i] > SL_HIST[tab + 2 * (i - 1)]); + assert(SL_HIST[tab + 2 * i + 1] >= SL_HIST[tab + 2 * (i - 1) + 1]); + i = i + 1; + } + t = t + 1; + } + // the long-rest end of each table is the settled delay the rest of the model uses (nor3 pin B at the delay cell's load, the delay cell's code 000) + assert(sl_err_pm(sl_h_get(SL_H_N2R, SL_AGE_INF), SL_DC_RISE[0]) <= 20); + assert(sl_err_pm(sl_h_get(SL_H_N2F, SL_AGE_INF), SL_DC_FALL[0]) <= 20); + assert(sl_err_pm(sl_h_get(SL_H_N1R, SL_AGE_INF), sl_arc(6, SL_RISE, SL_DC_LOAD_R)) <= 20); + assert(sl_err_pm(sl_h_get(SL_H_N1F, SL_H_REF_N1F), sl_arc(6, SL_FALL, SL_DC_LOAD_F)) <= 50); + // a table point is returned exactly; halfway between two points is their mean; flat below the first age and above the last + assert(sl_h_get(SL_H_N2R, 6034) == 5938); + assert(sl_h_get(SL_H_N2R, 6034 + (9194 - 6034) / 2) == (5938 + 6943) / 2); + assert(sl_h_get(SL_H_N2F, 100) == 6520); + assert(sl_h_get(SL_H_N2F, 5000000) == 8081); + // the younger the output, the shorter the delay of the cell and of its driver + assert(sl_h_get(SL_H_N2R, 3000) < sl_h_get(SL_H_N2R, 30000)); + assert(sl_h_get(SL_H_N1F, 10000) < sl_h_get(SL_H_N1F, 60000)); + assert(sl_h_get(SL_H_N2F, 12000) < sl_h_get(SL_H_N2F, 60000)); + assert(sl_h_get(SL_H_N1R, 5000) < sl_h_get(SL_H_N1R, 60000)); + // the age of an output: since its last change between two known values, a long rest if there was none (or it is in the future) + var ms : [5500]usize = [0] ** 5500; + ms[SL_TCH] = NONE; + ms[SL_TCH + 1] = 5000; + ms[SL_TCH + 2] = 9000; + assert(sl_age(&ms, 0, 7000) == SL_AGE_INF); + assert(sl_age(&ms, 1, 7000) == 2000); + assert(sl_age(&ms, 2, 7000) == SL_AGE_INF); +} + +test the_calibration_chains_are_reproduced_within_3_percent_and_not_exactly { + var c : usize = 0; + var worst : usize = 0; + while (c < 21) { + var ms : [5500]usize = [0] ** 5500; + var ids : [24]usize = [0] ** 24; + assert(sl_chain_run(&ms, &ids, SL_HC_WH[c], SL_HC_WL[c], 4, false, true)); + const f : usize = sl_chain_err_f(&ms, &ids, SL_HC_WH[c], SL_HC_WL[c], 3, SL_NG_HC_F[c]); + const r : usize = sl_chain_err_r(&ms, &ids, SL_HC_WH[c], SL_HC_WL[c], 3, SL_NG_HC_R[c]); + assert(f <= SL_CAL_BOUND_PM); + assert(r <= SL_CAL_BOUND_PM); + if (f > worst) { worst = f; } + c = c + 1; + } + // a fit through tabulated points, not a copy of them: the clkc delay also holds the inverter and the rest of the chain + assert(worst > 0); +} + +test held_out_pulse_spacings_are_within_the_bound_the_tables_never_saw_them { + // seven pulse trains, none of them in the calibration (h01 is the golden pace): every one of the six clkc falls and six rises + var c : usize = 0; + var worst_f : usize = 0; + var worst_r : usize = 0; + while (c < 7) { + var ms : [5500]usize = [0] ** 5500; + var ids : [24]usize = [0] ** 24; + assert(sl_chain_run(&ms, &ids, SL_HH_WH[c], SL_HH_WL[c], SL_HH_N, false, true)); + assert(sl_edges(&ms, ids[8], 0, SL_H_REST) == SL_HH_N); + assert(sl_edges(&ms, ids[8], 1, SL_H_REST) == SL_HH_N + 1); + var p : usize = 0; + while (p < SL_HH_N) { + const f : usize = sl_chain_err_f(&ms, &ids, SL_HH_WH[c], SL_HH_WL[c], p, SL_NG_HH_F[SL_HH_N * c + p]); + const r : usize = sl_chain_err_r(&ms, &ids, SL_HH_WH[c], SL_HH_WL[c], p, SL_NG_HH_R[SL_HH_N * c + p]); + assert(f <= SL_CLKC_BOUND_PM); + assert(r <= SL_CLKC_BOUND_PM); + if (f > worst_f) { worst_f = f; } + if (r > worst_r) { worst_r = r; } + p = p + 1; + } + c = c + 1; + } + assert(worst_f > 0); + assert(worst_r > 0); +} + +test the_last_fall_with_ck1_up_as_well_is_earlier_and_within_the_bound { + var ms : [5500]usize = [0] ** 5500; + var ids : [24]usize = [0] ** 24; + assert(sl_chain_run(&ms, &ids, 20200, 19800, 11, true, true)); + assert(sl_chain_err_f(&ms, &ids, 20200, 19800, 9, SL_NG_K1_F[0]) <= SL_CLKC_BOUND_PM); + assert(sl_chain_err_f(&ms, &ids, 20200, 19800, 10, SL_NG_K1_F[1]) <= SL_CLKC_BOUND_PM); + // ngspice's tenth fall takes 6958 ps and the eleventh 5741 ps: the model's eleventh is shorter than its tenth, by about as much + const t10 : usize = sl_edge(&ms, ids[8], 0, 10, SL_H_REST) - sl_chain_tr(20200, 19800, 9); + const t11 : usize = sl_edge(&ms, ids[8], 0, 11, SL_H_REST) - sl_chain_tr(20200, 19800, 10); + assert(t11 < t10); + assert(t10 - t11 > 1000); + assert(t10 - t11 < 1400); +} + +test negative_control_the_stateless_delay_cell_fails_the_repeated_fall_check_that_the_remembering_one_passes { + // the golden pace, six pulses: with the history the repeated clkc falls are within the bound; without it (the settled table of the first M4d) they are + // 83 to 90 % late + var ms : [5500]usize = [0] ** 5500; + var ids : [24]usize = [0] ** 24; + assert(sl_chain_run(&ms, &ids, 20200, 19800, SL_HH_N, false, true)); + var ms0 : [5500]usize = [0] ** 5500; + var ids0 : [24]usize = [0] ** 24; + assert(sl_chain_run(&ms0, &ids0, 20200, 19800, SL_HH_N, false, false)); + assert(ms[SL_HON] == 1); + assert(ms0[SL_HON] == 0); + var p : usize = 1; + while (p < SL_HH_N) { + assert(sl_chain_err_f(&ms, &ids, 20200, 19800, p, SL_NG_HH_F[p]) <= SL_CLKC_BOUND_PM); + assert(sl_chain_err_f(&ms0, &ids0, 20200, 19800, p, SL_NG_HH_F[p]) > 800); + p = p + 1; + } + // and at the fast pace the stateless cell is off by more than the bound too + var ms1 : [5500]usize = [0] ** 5500; + var ids1 : [24]usize = [0] ** 24; + assert(sl_chain_run(&ms1, &ids1, SL_HH_WH[1], SL_HH_WL[1], SL_HH_N, false, false)); + assert(sl_chain_err_f(&ms1, &ids1, SL_HH_WH[1], SL_HH_WL[1], 3, SL_NG_HH_F[SL_HH_N + 3]) > 1500); +}