Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .trinity/seals/analog_AnalogMosPsp103Data.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:b54bb70dcdaad8eac3180a3a51ee5d30d340b951edd734d4e817c161c1081f94",
"gen_hash_rust": "sha256:22cfdd782fe043555e0aa880bf922c2de502545f50aa5c92fb3e27fb0231fd2a",
"gen_hash_verilog": "sha256:f0e9948d7d18bf642dceae55962767fd570aea0a3c5dd0590d315566afc3509a",
"gen_hash_zig": "sha256:c9e11b43a265e022f096562ce39f6963dea17aa55489c83ccf2fc953ba1c186e",
"gen_hash_c": "sha256:83abce2660327df33c17d296932949f34452d4c2da56e9d585073079e3b6af7f",
"gen_hash_rust": "sha256:abdec74a2de33e2b249ef77300bc550827a82a3bda849fe2225b58df71ef8d7e",
"gen_hash_verilog": "sha256:1a459f8111272cef5616af605e2fa8500e76b86f24d2648606d6a352a309af82",
"gen_hash_zig": "sha256:a2d2c04035b7511edc876b496e7ebc0b417b35956a48783b22f1afb71ec4c5db",
"module": "AnalogMosPsp103Data",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-20T03:08:15Z",
"sealed_at": "2026-10-20T03:32:22Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:c4d59c5d87b03810373bfabb9024f4e1051184f3abab9a613e02ab0ae54848d9",
"spec_hash": "sha256:86e7c154c88a325e41ff4a154a3b766cb8d65e89e2ea82176b46ee4fc523dd74",
"spec_path": "specs/analog/mos_psp103_data.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 11,
"total": 11,
"passed": 12,
"total": 12,
"vacuous": 0
},
"toolchain": {
Expand Down
53 changes: 53 additions & 0 deletions .trinity/seals/fpga_FpgaPsp103Inv.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"built_by": "t27c-bootstrap@0.5.2+42a4860c4",
"closure": [
{
"spec": "specs/analog/linear.t27",
"spec_hash": "sha256:3ddef7be183aba583ed285334ee389b48a65b41335e98914514235db7c4e5d62"
},
{
"spec": "specs/analog/mos_psp103.t27",
"spec_hash": "sha256:e04b69e5c43188a3d46a4c0949cfc727f239721de73fb46e92c8a845bbbbc98e"
},
{
"spec": "specs/analog/mos_psp103_data.t27",
"spec_hash": "sha256:86e7c154c88a325e41ff4a154a3b766cb8d65e89e2ea82176b46ee4fc523dd74"
},
{
"spec": "specs/analog/mos_table.t27",
"spec_hash": "sha256:54e248069ae620d18d260231e238b6bc42dc3c65792bd1673b162c2dc97b2edb"
},
{
"spec": "specs/fpga/rc_filter_ax7203.t27",
"spec_hash": "sha256:be3af1aa6195d51e46289121cfd42623c80cd42d863442f4f6f69109da06d32f"
},
{
"spec": "specs/fpga/sar_adc_ax7203.t27",
"spec_hash": "sha256:4db9099fe0019743e3300f8281fffcfe33ad653d7f953dee149749ee7d332888"
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:b771fb1b1fcc4f15da4406867270ee816694efc0599624dfffbbbb27d8b8646c",
"gen_hash_rust": "sha256:6f3c61044f101192974b16e4cc2370fb521d030cfbb7db75d6a5c9cbd37c8c46",
"gen_hash_verilog": "sha256:01be0dc34ed7c33c9db90ae2017f7a12a4da24da08b5abd5ffdda186fb590c8d",
"gen_hash_zig": "sha256:1dc394384cd096057be4350fa242682fde32dea71336bafd54a334de8a06d3ff",
"module": "FpgaPsp103Inv",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-20T03:38:21Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:7b0a701839d65311137e8e03e564b0d60526286090390683f912592a3391dd4c",
"spec_path": "specs/fpga/psp103_inv_ax7203.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 15,
"total": 15,
"vacuous": 0
},
"toolchain": {
"test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10",
"zig": "0.16.0"
}
}
10 changes: 5 additions & 5 deletions .trinity/seals/fpga_FpgaSarAdc.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"built_by": "t27c-bootstrap@0.5.2+ea35d9b72",
"built_by": "t27c-bootstrap@0.5.2+42a4860c4",
"closure": [
{
"spec": "specs/analog/linear.t27",
"spec_hash": "sha256:3ddef7be183aba583ed285334ee389b48a65b41335e98914514235db7c4e5d62"
},
{
"spec": "specs/analog/sar_adc.t27",
"spec_hash": "sha256:48e8825a4a6a7fc24ce23472bcba5499dcafbd399ac45a14fb153a0a020018e2"
"spec_hash": "sha256:208a64705a1d07ff14d3131d999135a3d5da6c7cb9bc2e919430d7e60b34db68"
},
{
"spec": "specs/analog/sar_cdac.t27",
Expand All @@ -22,13 +22,13 @@
"gen_hash_c": "sha256:cb648c123b7e68b21c2d3104308014a597c781f7bd9c74c60ca2bcf399e49ccb",
"gen_hash_rust": "sha256:d1801d59922c582d2ddbed1d68ea6eec5f5957852c725ad3bc9b899062a7a5d1",
"gen_hash_verilog": "sha256:30e45f0b102e0d2da8590d230deccad81ef5fd16ecdb0ea20438a2d9734f7f77",
"gen_hash_zig": "sha256:81b4bfac62fcdde580527a093ce82df500c4ad86e08b098ad19217ffb7694c11",
"gen_hash_zig": "sha256:92d85db28d226f9dbafbe5ea6c949ebd7c6050e4ab7883eecc26b2b8627c2795",
"module": "FpgaSarAdc",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T07:59:22Z",
"sealed_at": "2026-10-20T03:38:27Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:54c6f2c7e86c000f060cf8efab0123386431999ae803b285d364011b5aa89691",
"spec_hash": "sha256:4db9099fe0019743e3300f8281fffcfe33ad653d7f953dee149749ee7d332888",
"spec_path": "specs/fpga/sar_adc_ax7203.t27",
"tests": {
"failed": 0,
Expand Down
121 changes: 121 additions & 0 deletions docs/analog/board-psp103-inv-2026-10-20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Board run of the PSP103 inverter, tt corner, tables in block RAM, 2026-10-20

Issue #11208 (M3d, success criterion SC-003 of the analog epic #10486), a lane of the night loop #11063. English, ASCII only.

This is the first analog board top that reads the PSP103 tables: `specs/fpga/psp103_inv_ax7203.t27` runs the 500 fF CMOS inverter of `specs/analog/mos_psp103.t27` (400 backward Euler steps of dt = 100 ps, tt current and drain-charge tables, three Newton iterations a step) on the ALINX AX7203, holds the four tables and the 400 expected samples in block RAM, and prints one UART line per step. Every number below was measured in this run.

What this document does not say: nothing about speed, power or value. Fmax is nextpnr's post-route estimate for one placement of one netlist. A PASS says the board agrees with the spec's own fixed-point run, which `mos_psp103.t27` puts within 0.020 % (rise) and 0.0041 % (fall) of ngspice's 50 % delays at tt; it does not say anything about another corner, another load or another gate waveform.

## 1. The run

- Source: the specs as committed at `8e76e1b1a` on `lane/m3d-11208` (`psp103_inv_ax7203.t27`, and `mos_psp103_data.t27` with its clocked port and `TT_RUN`). Nothing was edited between the commit and the build; the control is a scratch copy (section 2).
- Compilers: `t27c` sha256 `016fb83b7f02d045...` and `t27b` sha256 `d7ec5790dc29b3f3...`, the release binaries of the shared build directory.
- Toolchain: yosys 0.63 (git 70a11c6bf0e8dd669f56c7da3587f78b405138e2), the openXC7 fork of nextpnr-xilinx and prjxray from the shared build directory, chipdb `xc7a200tfbg484-2.bin` (md5 `59f828c441e6e6081bfee63ff994660e`), `openFPGALoader v1.1.1`.
- Board and cable: ALINX AX7203, `xc7a200tfbg484-2`. `t27c boards` named the cable: `--busdev-num 1:4 idcode 0x3636093 family artix a7 200t` (Digilent HS2, FT232H). UART: the CP2102N bridge of the board, 115200 baud 8N1, pin N15, read by one reader from the terminal tab of the desktop app, started before the load; the port was free before and after.
- Programming: SRAM only (`openFPGALoader` without `-f` or `-m`; the output shows `Load SRAM` and `done 1`). No flash memory and no eFUSE was written.
- Disk: free space on `/` was 5.3 to 6.5 GiB during the run (the lane brief's floor is 5 GiB); each 22 MB frames file was deleted once its bitstream existed.

## 2. How it was built

`$O` is the shared openXC7 build directory, `$B` a scratch output directory.

```
t27b verilog specs/fpga/psp103_inv_ax7203.t27 > $B/top.v # 1215 lines, module FpgaPsp103Inv
t27c gen-verilog specs/analog/mos_psp103_data.t27 > $B/data.v # 39959 lines, module AnalogMosPsp103Data
yosys -l $B/x.log $B/x.ys
# x.ys:
read_verilog -sv $B/top.v $B/data.v
synth_xilinx -family xc7 -top FpgaPsp103Inv -flatten -abc9 -nodsp -nosrl -run :coarse
techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=6
alumacc
opt
memory -nomap
opt_clean
setattr -set ram_style "block" t:$mem_v2
synth_xilinx -family xc7 -top FpgaPsp103Inv -flatten -abc9 -nodsp -nosrl -run map_memory:
stat
write_json $B/x.json
$O/np-main/build/nextpnr-xilinx --chipdb $O/xc7a200tfbg484-2.bin --json $B/x.json --fasm $B/x.fasm --freq 100 [--seed 2] --log $B/x.pnr.log
PYTHONPATH=$O/prjxray $O/venv/bin/python3 $O/prjxray/utils/fasm2frames.py --db-root $O/prjxray-db/artix7 --part xc7a200tfbg484-2 $B/x.fasm $B/x.frames
$O/px-main/build/tools/xc7frames2bit --part_file $O/prjxray-db/artix7/xc7a200tfbg484-2/part.yaml --part_name xc7a200tfbg484-2 --frm_file $B/x.frames --output_file $B/x.bit
openFPGALoader -c digilent_hs2 --busdev-num 1:4 $B/x.bit # SRAM only
```

The pins are attributes in the spec, so there is no constraint file and no hand-written Verilog: the board top is `t27b verilog` output, the RAM is `t27c gen-verilog` output. The one line that is not in the spec is `setattr -set ram_style "block"`, a yosys directive in the build script (see section 6).

The negative control is the same `top.v` and a `data.v` generated from a scratch copy of `mos_psp103_data.t27` whose `on_clock` reads `SS_N`, `SS_P`, `SS_QD_N`, `SS_QD_P` instead of the four `TT_` tables (the copy lived in `specs/analog/` for one command, because a `use` does not resolve elsewhere, and was deleted). The two generated `data.v` files differ in exactly four lines, the four table reads. The expected samples (`TT_RUN`) are the tt ones in both.

## 3. The board table

| | tt top | ss control |
|---|---|---|
| `top.v` sha256 | `5bf24f964e7f59358b02a5a931a72c51b01255c04c1ec310e082eda1d5abd84e` | the same |
| `data.v` sha256 | `91a80c709ab09eb99bb09bcc18d833c3cd5c084dcddc2f35e0014b4cec9c6dd0` | `12b85f1c16f12127...` |
| LUT (yosys, LUT2..LUT6) | 1426 (LUT2 461, LUT3 172, LUT4 165, LUT5 334, LUT6 294; plus 170 INV) | 1422 (468, 198, 198, 311, 247; plus 170 INV) |
| FF | 1219 (FDRE 1196, FDSE 23) | 1219 (1196, 23) |
| DSP48E1 | 0 | 0 |
| BRAM | 4 RAMB36E1 + 1 RAMB18E1 (the four 625-word tables and the 400-word run) | 4 RAMB36E1 + 1 RAMB18E1 |
| LUT ROM | none: the tables are in block RAM, not in LUTs | none |
| CARRY4 (yosys / nextpnr) | 207 / 211 | 207 / 211 |
| nextpnr SLICE_LUTX / SLICE_FFX | 2768 / 1219 of 269200 | 2764 / 1219 |
| Fmax before routing (first line) | 72.73 MHz (FAIL at 100) | 78.61 MHz (seed 2) |
| Fmax after routing (second line) | **103.61 MHz** (PASS at 100) | **107.33 MHz** (PASS at 100), seed 2; seed 1 gave 96.57 MHz (FAIL) |
| frames file | 20230 lines, no fasm2frames error | 20230 |
| receipt lines, well-formed | 1217 (L = 0 to 1216, no gap) | 1217 (L = 0 to 1216, no gap) |
| lines whose Y equals the spec's sample | 1217 of 1217 (tt run) | 1217 of 1217 (ss run) |
| PASS / FAIL | **1217 / 0** | 231 / 986 |
| a complete round (N = 0 .. 399) | 400 of 400 PASS, S at N = 18F `0x215DC5EAC4C48576` = `EXP_S_TT_Q` | 77 PASS, 323 FAIL, S at N = 18F `0x987F22AC4132345B` = `EXP_S_SS_Q` |

Resources are the same order as the SAR top (908 LUT, 538 FF) plus the multiplier, the divider and the 64-bit accumulators; the tables cost no LUT.

## 4. The captures

Each capture is 7 seconds, one reader, started before the load. A line is well-formed when it matches `T27 PSP N=<3 hex> Y=<7 hex> E=<7 hex> S=<16 hex> L=<4 hex> (PASS|FAIL)` exactly; only well-formed lines are counted. Before the new configuration took over, the previous design on the board was still printing: in the tt capture 17 lines of the SAR top and a fragment, in the control capture ten whole lines of the tt top (L = 0xD4F6 and up) and three fragments. The last line of each capture is cut where the reader is killed. Those are the only malformed lines, and the first line of our design, `L=0000`, is intact in both captures (it follows the cut tail of the previous design's line on the same text line; the judge looks for the receipt grammar inside a line and starts at the first `N=000 .. L=0000` line, and says how many lines of the previous design it dropped: 0 for the tt capture, 10 for the control).

| | tt top | ss control |
|---|---|---|
| capture bytes / sha256 | 81485, `b34dafeae9e75c46...` | 81221, `bc4d0dfa86f7be9e...` |
| bitstream sha256 (header carries a time) | `29994e0d605d6812...` | `8f8db254206f496c...` |
| lines starting with `T27 ` | 1235 | 1230 |
| well-formed lines of the design | 1217 | 1217 |
| N sequence | 0, 1, .., 399, 0, 1, .. with no break | the same |
| S of every line = fold of the spec's samples up to N | 1217 of 1217 | 1217 of 1217 (ss samples) |
| verdict differs from the spec's prediction | 0 of 1217 | 0 of 1217 |

First lines of the tt capture and the control, for the record:

```
tt T27 PSP N=000 Y=00A8451 E=00A8451 S=00000000000A8451 L=0000 PASS
T27 PSP N=001 Y=019C356 E=019C356 S=00000000000CCBF4 L=0001 PASS
control T27 PSP N=000 Y=009C1F2 E=00A8451 S=000000000009C1F2 L=0000 FAIL
T27 PSP N=001 Y=017FB6A E=019C356 S=000000000004788E L=0001 FAIL
```

### The control, step by step

`mos_psp103.t27`'s own ss run (`run_fix_q` on `SS_N`, `SS_P`, `SS_QD_N`, `SS_QD_P` from the tt rest value of 3 units) differs from the tt run at 323 of the 400 steps: every step except 145 (the one place the ss output crosses the tt output) and 324 to 399 (both back at the rest value). A test in `psp103_inv_ax7203.t27` pins that (`CTRL_FAILS`, `CTRL_PASS_AT`, `CTRL_SETTLED_FROM`, `EXP_S_SS_Q`) and a second test runs the machine on the ss tables and gets the same verdicts. On the board:

| | predicted | measured |
|---|---|---|
| FAIL steps in a round | 323: N = 0 .. 144, 146 .. 323 | the same 323 steps, in every one of the three rounds |
| PASS steps in a round | 77: N = 145 and 324 .. 399 | the same 77 |
| Y on every line | the ss run's sample | 1217 of 1217 |
| S at N = 18F | `EXP_S_SS_Q` = `0x987F22AC4132345B` | `0x987F22AC4132345B` |

## 5. Tests

`t27c test-report specs/fpga/psp103_inv_ax7203.t27`: 15 tests, 15 pass, 0 fail, 0 vacuous (runtime asserts per test from 11 to 14482). `t27c test-report specs/analog/mos_psp103_data.t27`: 11 tests, 11 pass, 0 fail, 0 vacuous. `t27b test specs/fpga/psp103_inv_ax7203.t27 --check` and `t27b test specs/analog/mos_psp103_data.t27 --check` exit 0; for the board top t27b prints `runtime asserts unknown`, because its interpreter's fuel (20 million steps a file, `specs/tri/t27b/check_budget.t27`) runs out in the whole-run tests (a 400-step run is about 760000 clocks, and the UART test and the control run it again): the JIT ran all 15 tests and they pass; the interpreter agrees on the part it had fuel for.

## 6. What differed from the plan, and traps

1. **`t27c gen-verilog` writes nothing for an array that came in by `use`.** The reference is left undeclared (the same defect #8769 records for functions), so the tables could not be read from the board spec. The memory is therefore generated from the module that owns the arrays: `mos_psp103_data.t27` got a clocked port next to them (`on_clock(addr, idx)`, five output registers) and the board top instantiates it as an extern, like the PLL. A minimal repro for #5980: a spec with `use analog::mos_psp103_data::{TT_N};` and `on_clock` reading `TT_N[addr]` generates Verilog with `TT_N` undeclared.
2. **yosys maps a 625-word ROM to flip-flops and LUTs** (about 1270 LUT, 909 of them LUT6, and 79 FDRE for the four tables in a probe) unless the memory carries `ram_style = "block"`; with it the same module is 4 RAMB36E1 and no LUT. `gen-verilog` cannot write the attribute, so the build script sets it with `setattr` on the `$mem_v2` cells. Worth a rule in `gen-verilog` (an attribute on a const array that the spec marks) or in `t27c silicon`.
3. **A `const rst_n` in a `gen-verilog` module makes yosys refuse the process** (`negedge` of a constant: "Multiple edge sensitive events found"). The data module leaves `rst_n` and `en` as ports and the top ties them to 1, which `flatten` and `opt` fold into plain flip-flops, so the memory's read register merges into the block RAM.
4. **Names of module vars must not collide with locals of imported functions** (`acc`, `y0`, `lo`, `hi`, `cx`, `fx`: `blend`, `id_of` and the rest declare them): t27b refuses a local that shadows a module var. The datapath registers are `r_`-prefixed.
5. **Read before write.** `on_clock` assigns with non-blocking semantics in hardware; the tests run it sequentially, so a var read after its own assignment in the same call (a counter incremented, then compared) passes in hardware and fails in the test or the reverse. Two such places were found by the divider test and reordered.
6. **The control missed timing once**: with the default seed the ss build reached 96.57 MHz after routing (FAIL at 100); seed 2 gave 107.33 MHz. The tt top closed at the default seed.
7. The reader attached before the load saw the previous design's lines; the judge starts at the first `L=0000`, `N=000` line.

## 7. Not claimed

No speed claim (a step is about 1700 to 1960 clocks, 19 us at 100 MHz; the line of a step is 5.7 ms of UART; nothing here is compared with ngspice's wall time). No power. tt only: the other four corners are other tables and no other bitstream was built. One gate waveform (two levels, an ideal step), one load (500 fF with dt = 100 ps). The expected samples are the spec's own output stored in the RAM, so a PASS is agreement with the spec, not with ngspice; the spec's distance to ngspice is the one `mos_psp103.t27` measures.
Loading
Loading