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); +}