docs(spi): record SPI-P4B evidence and review closure

Record the sub-stage B command/verdict matrix for both profiles and both simulators, the SRAM/PSRAM V22 measurements, the live-admission root cause and repair, the partial-abort oracle and progress-reassembly corrections, the independent review findings (exact abort-length enforcement, new negative fixtures) and their closure, and the remaining gaps (Icarus full-A geometry, legacy LCD/LVGL gate absence, check-rtl-lint baseline absence, synthesis/netlist/STA/physical deferred to SPI-P5). phase_accepted stays false; the rejected 14:51 run remains labeled as rejected.
This commit is contained in:
maksyuki committed 2026-10-28 10:31:55 +08:00
1 parent 868452f3db
commit 31e386143f
2 files changed
+466 -17

No files matched your search

+140 -15
View File
@@ -3,10 +3,10 @@
SPI-P4 covers the frozen display path on top of the committed SPI-P3
integration: a project-owned ST7789VI-style four-wire adapter in
`app/board/`, an independent pin-level panel oracle in the Tiny testbench,
and the `TINY_SPI_P4_ACCEPTANCE` image covering the display-pattern stages.
Camera/PSRAM-source display and the sequential SD snapshot evidence are
sub-stage B; their frozen cases additionally require R2-P8/R2-P9 human
acceptance, which is pending at preflight time.
and the `TINY_SPI_P4_ACCEPTANCE` image covering the display-pattern and
snapshot stages. Camera/PSRAM-source display and sequential SD snapshot
evidence are sub-stage B; R2-P8/R2-P9/P10 human acceptance is recorded in
[tiny-soc-verification.md](tiny-soc-verification.md) on 2026-10-25.
## Interface contract
@@ -23,21 +23,146 @@ acceptance, which is pending at preflight time.
## Stages and evidence
The acceptance image (`app/apps/ci_smoke/tiny_spi_p4.c`) runs: discovery,
GPIO/SPI configuration, acquire with GPIO_READY, panel init, stage 1 color
bars and stage 2 gradient (full 320x240), stage 3-5 odd rectangles, stage 6
rotation variant (MADCTL=0x60), an abort/recover case (truncated full-frame
then a final clean window), release, and TEST_STATUS before the UART summary.
Sub-stage A runs discovery, GPIO/SPI configuration, acquire with GPIO_READY,
panel init, stage 1 color bars and stage 2 gradient (full 320x240), stage 3-5
odd rectangles, stage 6 rotation variant (MADCTL=0x60), and an abort/recover
case with a truncated full-frame followed by a clean final window. The QUICK
Icarus variant reduces only these A delays/full-window geometries.
Sub-stage B then releases SPI and runs, in order:
1. NSS1 PSRAM initialization/capacity validation, native-SD initialization,
and QVGA DVP capture into `0x54010000` with prefix/suffix guards.
2. Exact DVP/DMA completion checks, camera stop, full PSRAM readback against
the independent `(column_byte + 3 * row) & 255` camera pattern, and a
byte-normalized RGB565 FNV-1a record.
3. SPI/DMA3 reacquisition and a direct immutable-PSRAM display, followed by an
SRAM-source display of the same frame using 150 bounded chunks in one
held-CS panel window and one 1024-byte workspace. The final chunk releases
CS normally. The source remains immutable; no 150 KiB SRAM frame
exists. Each source has cycle, instruction, utilization, FIFO and stall
records plus passive DMA transaction/latency observations.
4. Native SD save/readback at LBA16..315 in 150 two-sector chunks with bounded
aligned transmit/receive buffers and full comparison against both PSRAM and
the independent camera words. SD and panel checksums use the same logical
big-endian pixel normalization, not the different P10 word-wise checksum.
5. A bound-DMA abort after partial PSRAM display, complete drain, RECOVER,
release/reacquire, final resource release, and TEST_STATUS before the UART
summary. New B failures use distinct result codes 9..18.
The A abort is exactly 544 pixels and the B abort is exactly 143 pixels. The
checker rejects every other aborted prefix length, including zero and other
nonzero values, with an explicit window/actual/expected problem message.
The SPI HAL exposes checked 64-bit transport arithmetic, single-beat DMA
bind/start/wait operations, exact completion checks, and separate wire-abort
versus bound-job abort/drain operations. It reads the existing CLOCK_HZ, DIV,
FIFO and stall registers; the register ABI is unchanged. The board adapter
binds TX DMA after the CPU RAMWR command and before pixel ARM. A timeout never
releases buffer or channel ownership implicitly.
The testbench panel model (`rtl/tiny/dv/tiny_st7789_panel.sv`, active with
`+tiny_spi_p4`) decodes the pins independently and emits SPI_P4_CMD,
SPI_P4_WINDOW (geometry, pixel count, FNV-1a, abort flag), SPI_P4_VIOLATION
and a terminal SPI_P4_PANEL summary. `scripts/spi_p4.py check --log` recomputes
the golden geometry/pixel checksums and rejects any drift; verdicts remain
and a terminal SPI_P4_PANEL summary. B adds two complete QVGA camera windows
and one aborted camera prefix to A's eight windows. `scripts/spi_p4.py check`
auto-detects A or A+B, independently recomputes all checksums and validates
capture, SD, measurement and P10 bus records. Archived A-only logs remain
supported with `--version a`, optionally with `--quick`. Verdicts remain
TEST_STATUS/`SIM_TEST_PASS` with no forbidden markers.
Focused checks: `make CONFIG=<profile> APP=ci_smoke TINY_SPI_P4_ACCEPTANCE=YES spi-p4-lint spi-p4-rtl spi-p4-report`.
Acceptance: `make CONFIG=<profile> APP=ci_smoke TINY_SPI_P4_ACCEPTANCE=YES TINY_SIM_ARGS=+tiny_spi_p4 firmware sim`.
Focused checks:
```sh
make CONFIG=<profile> APP=ci_smoke TINY_SPI_P4_ACCEPTANCE=YES \
spi-p4-lint spi-p4-rtl spi-p4-report
```
Full A+B Verilator example (budgets are execution ceilings, not performance
limits or FPS claims):
```sh
make CONFIG=<profile> APP=ci_smoke TINY_SPI_P4_ACCEPTANCE=YES \
TINY_SIM_TIMEOUT=300000000 SOC_SIM_TIME=28800 \
TINY_SIM_ARGS='+tiny_spi_p4 +tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p10_camera' \
firmware sim
python3 scripts/spi_p4.py check --variant-root build/<variant> --pdk <PDK> \
--log build/<variant>/sim/verilator/sim.log
```
The live SPI DMA admission repair and its focused evidence are recorded in
[spi-verification.md](spi-verification.md). Both Verilator A+B profiles pass
`SIM_TEST_PASS` and the independent checker with zero panel violations. This
establishes the V21/V22 functional result on those profile/simulator pairs only,
not the complete simulator matrix or physical qualification.
## Icarus QUICK-A/full-B execution
Icarus reduces only sub-stage A through the committed `RS_ST7789VI_QUICK`
path. Capture, both display sources, SD save/readback and abort handling retain
the full B workload. Use the separate P9 monitor when progress visibility is
required:
```sh
make CONFIG=<profile> APP=ci_smoke SIMU=IVERILOG \
TINY_SPI_P4_ACCEPTANCE=YES \
TINY_SIM_TIMEOUT=300000000 SOC_SIM_TIME=288000 \
TINY_SIM_ARGS='+tiny_spi_p4 +tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p10_camera +tiny_p9_monitor +tiny_p9_monitor_log=<absolute-monitor-path>' \
firmware sim
python3 scripts/spi_p4.py check --variant-root build/<variant> --pdk <PDK> \
--quick --log build/<variant>/sim/iverilog/sim.log
```
`SOC_SIM_TIME=288000` records the extended wall budget; the cycle ceiling stays
at 300000000. Launch long simulations detached without an outer tool timeout,
and poll the structured result and logs. Silence or slow progress is not hang
evidence.
Prefer `+tiny_p9_monitor` over `+tiny_p9_progress` for strict acceptance. The
latter shares stdout with the character-at-a-time Icarus UART observer and can
split acceptance records. The checker losslessly reassembles only complete,
well-formed progress interruptions, including their newline, while preserving
all other characters in order. Malformed observer text and truncated/corrupted
SPI records are rejected; no check is relaxed. Never edit or filter the raw log.
The committed `tiny_p9_monitor` instead writes progress to its own file and never
calls `$finish`, avoiding the hazard at its source.
## Matrix checkpoint (2026-10-26)
The exact commands, checker records and regression evidence are in the
[sub-stage B matrix checkpoint](spi-verification.md#spi-p4-sub-stage-b-matrix-checkpoint-2026-10-26).
The current verdicts are:
- PASS: ICS55 Verilator at
`build/ics55-tiny-2026-10-25-20-05-35b6184dae5c/`, 94425948 cycles.
- PASS: IHP130 Verilator at
`build/ihp130-tiny-2026-10-26-01-16-995377fb20d0/`, 94425948 cycles.
- PASS: ICS55 Icarus at
`build/ics55-tiny-2026-10-26-11-19-35b6184dae5c/` completed naturally with
`SIM_TEST_PASS Tiny cycles=53810943`, exit 0 and 121321.334 s wall time. No
forbidden marker is present. Lossless reassembly of the progress interruptions
preserves the full B records, and the QUICK checker exits 0 with
`problems=[]`. The original traceback and raw log remain retained as observer
hazard evidence.
- PASS: IHP130 Icarus at
`build/ihp130-tiny-2026-10-26-15-20-995377fb20d0/` completed naturally with
`SIM_TEST_PASS Tiny cycles=53810943`, exit 0 and 114295.959 s wall time. No
forbidden marker is present, and lossless reassembly lets the QUICK checker
pass with `problems=[]`. The interrupted 04:43 attempt remains retained
separately as exit 130 after its outer tool timeout, not as hang evidence.
- PASS: P3 Verilator on both profiles at 1050629 cycles, under
`build/ics55-tiny-2026-10-26-01-19-d1eafd9db70e/` and
`build/ihp130-tiny-2026-10-26-01-20-e29716f7754c/`.
The independent review's P1 variable-abort-length finding is closed by exact
544/143 enforcement and wrong-prefix negative tests. Its P3 coverage finding is
closed by complete-window odd-byte and non-pixel residual fixtures on both
simulators. The focused suite passes 22 tests; all four accepted logs still pass.
The final full host suite reports 2124 passed and one optional `pypdf` skip.
See the [review closure](spi-verification.md#independent-review-closure-2026-10-28)
for evidence. No long simulation was rerun.
Pre-final timing stays observational under the 2026-10-07 policy; SPI-P5
remains the final physical qualification phase. `phase_accepted` is false
until human review.
remains the final physical qualification phase. Full-A Icarus geometry, a
dedicated legacy-LCD/LVGL acceptance gate, complete netlist/STA/physical
qualification and human review remain open. `phase_accepted` is false.
+326 -2
View File
@@ -153,8 +153,332 @@ cycle/payload measurements. Full Pytest: 2102 passed, 1 skipped (optional
`pypdf`), 0 failed in 4442.19 s.
Sub-stage B (V21/V22: PSRAM-source display, sequential capture/verify/SD,
SRAM-vs-PSRAM performance) remains gated on R2-P8/R2-P9 human acceptance.
SPI-P5 stays deferred; `phase_accepted` stays false.
SRAM-vs-PSRAM performance) is authorized by the R2-P8/R2-P9/P10 human
acceptance recorded on 2026-10-25 in
[tiny-soc-verification.md](tiny-soc-verification.md#tiny-r2-p8p9p10-human-acceptance-2026-10-25).
Its implementation and fresh evidence remain a separate work item; this note
does not relabel the accepted sub-stage A results as B coverage. Initial B
bring-up on `dev@76901df4` passed A, QVGA capture/readback and PSRAM display,
then failed the first SRAM chunk with result code 14 after 13054.528 s
(`build/ics55-tiny-2026-10-25-07-52-35b6184dae5c/`). A QUICK-A diagnostic
reproduced the failure after 5318.140 s
(`build/ics55-tiny-2026-10-25-11-43-35b6184dae5c/`): SPI fault 4, TX FIFO
level 8, and a write error at `0x1001d054`. The integrated DMA statically
enabled the SPI request-ready inputs and had no SPI-to-DMA backpressure path,
so fast SRAM jobs overflowed the frozen credit contract. This was a P2/P3
integration omission, not a firmware-data failure or an architecture
contradiction; no smaller-job workaround or verdict relaxation is accepted.
The repair exposes live TX/RX admission from `apb4_spi`, passes it through
`apb4_dma`, and uses it only for SPI request readiness. Admission requires the
corresponding enabled binding, FIFO data/capacity, and no pending credit or
response. `spi_start_pending_o` follows registered busy SPI jobs rather than
readiness-filtered arbiter candidates, preserving binding/drain coverage without
a combinational readiness loop. The DMA scheduler, bursts, credit reservation/
retirement, and register ABI are unchanged. Mini ties the new input to zero and
keeps SPI disabled; the SPI-enabled P9 fixture ties both bits to preserve its
prior standalone behavior.
The production-IP dynamic fixture proves TX-full and RX-empty stalls, delayed
R/B retirement, an in-flight B response across both abort commands, drain and
RECOVER, release/reacquire, clean TX pixels, and RX data/tail integrity on both
Verilator and Icarus. Each final focused stage passes 19 tests, including this
fixture and the panel-oracle cases
(`build/ics55-tiny-2026-10-25-20-05-35b6184dae5c/meta/spi-p4/`). Tiny lint has
no `UNOPTFLAT`; Mini lint and DMA prove/cover also pass, in 131.497 s and
67.543 s respectively (`build/ihp130-2026-10-25-14-51-f1560e642e06/`). Eleven
affected DMA/WS2812/P9 consumer tests and the RTL formatter/owned-style checks
also pass. The separate `check-rtl-lint` command still fails because the
committed ICS55 Tiny warning baseline is absent, not because of a
repair-specific diagnostic; no baseline was edited.
An intermediate full A+B run reached `SIM_TEST_PASS Tiny cycles=94360540` but
was correctly rejected by the independent checker
(`build/ics55-tiny-2026-10-25-14-51-35b6184dae5c/`): code 1 marked CS rising
with residual bits during the legal B partial-frame abort, and the 128-cycle
done delay ended before `SPI_P4_RESULT` could be transmitted. The frozen SPI-P1
contract explicitly includes a valid partial-frame abort. The panel model now
distinguishes that case from an invalid complete-window truncation, while
unexpected aborts and residual bits after a complete window remain rejected.
The new oracle fixture passes both simulators with two legal partial aborts and
one invalid residual-bit case. The P4 done limit is now 65536 cycles, allowing
the required UART result without changing TEST_STATUS ordering or checker
expectations.
Final ICS55 Verilator A+B evidence passes both required gates
(`build/ics55-tiny-2026-10-25-20-05-35b6184dae5c/`): `SIM_TEST_PASS Tiny
cycles=94425948`, no forbidden markers, and `spi_p4.py check` exits zero with an
empty problem list (`meta/spi-p4/check/record.json`). The panel reports 42
commands, 11 windows, FNV-1a `0x85007c9e`, and zero violations. SD save/readback
passes 150 chunks/300 blocks/153600 bytes with FNV `0xc198adc5`; the B abort
prefix is 143 pixels with `aborted=1`. `SPI_P4_RESULT` reports code 0 and the
simulator wall time is 17936.478 s.
V22 measurements at SCK 12000000 Hz are:
- PSRAM: 3434872 frame/CPU cycles, 572592 instructions, 143119666 ns,
715485 ppm utilization, TX stalls 885796, longest TX wait 235, DMA stalls
3264041, FIFO min/max/final 0/0/0, one chunk.
- SRAM: 7394659 frame/CPU cycles, 895851 instructions, 308110791 ns,
332347 ppm utilization, TX stalls 380250, longest TX wait 0, DMA stalls
2266350, FIFO min/max/final 2/8/0, 150 chunks.
Each display window has exactly 38400 central-DMA reads and writes and 153600 B
in each direction. Passive maximum read/write latency is 77/18 cycles for PSRAM
and 5/18 for SRAM. P9 accepted/delivered words are both 38400. Icarus, the full
simulator matrix, and physical qualification remain separate obligations;
SPI-P5 stays deferred and `phase_accepted` stays false.
## SPI-P4 sub-stage B matrix checkpoint (2026-10-26)
The matrix uses the dirty `dev@76901df4400b9a92918a8a8ed49cf849f751f423`
worktree containing the admission repair and the partial-abort/done-limit
corrections above. No commit, warning-baseline or verdict-rule change was made.
The 14:51 run remains rejected; its TEST_STATUS marker is not acceptance.
### Simulation commands and verdicts
ICS55 Verilator A+B:
```sh
make CONFIG=configs/ci/ics55-tiny.mk APP=ci_smoke TINY_SPI_P4_ACCEPTANCE=YES \
BUILD_TIMESTAMP=2026-10-25-20-05 TINY_SIM_TIMEOUT=300000000 SOC_SIM_TIME=28800 \
TINY_SIM_ARGS='+tiny_spi_p4 +tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p10_camera' \
firmware sim > build/spi_p4_full_2005.log 2>&1
python3 scripts/spi_p4.py check \
--variant-root build/ics55-tiny-2026-10-25-20-05-35b6184dae5c --pdk ICS55 \
--log build/ics55-tiny-2026-10-25-20-05-35b6184dae5c/sim/verilator/sim.log
```
PASS: exit 0, no forbidden markers, 94425948 cycles, checker `problems=[]`, and
`phase_accepted=false`. The root is
`build/ics55-tiny-2026-10-25-20-05-35b6184dae5c/`; simulator wall time is
17936.478 s.
IHP130 Verilator A+B:
```sh
make CONFIG=configs/ci/ihp130-tiny.mk APP=ci_smoke TINY_SPI_P4_ACCEPTANCE=YES \
BUILD_TIMESTAMP=2026-10-26-01-16 TINY_SIM_TIMEOUT=300000000 SOC_SIM_TIME=28800 \
TINY_SIM_ARGS='+tiny_spi_p4 +tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p10_camera' \
firmware sim > build/spi_p4_ihp130_verilator_0116.log 2>&1
python3 scripts/spi_p4.py check \
--variant-root build/ihp130-tiny-2026-10-26-01-16-995377fb20d0 --pdk IHP130 \
--log build/ihp130-tiny-2026-10-26-01-16-995377fb20d0/sim/verilator/sim.log
```
PASS: exit 0, no forbidden markers, 94425948 cycles, checker `problems=[]`, and
`phase_accepted=false`. The root is
`build/ihp130-tiny-2026-10-26-01-16-995377fb20d0/`; simulator wall time is
12303.707 s. Capture is 76800 pixels/153600 bytes/38400 words, SD is 150
chunks/300 blocks with readback=1, and the B abort prefix is 143 pixels, all
matching the ICS55 accepted run. Both logs carry the same V22 measurements
above.
The active ICS55 Icarus command is:
```sh
make CONFIG=configs/ci/ics55-tiny.mk APP=ci_smoke SIMU=IVERILOG \
TINY_SPI_P4_ACCEPTANCE=YES BUILD_TIMESTAMP=2026-10-26-11-19 \
TINY_SIM_TIMEOUT=300000000 SOC_SIM_TIME=288000 \
TINY_SIM_ARGS='+tiny_spi_p4 +tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p10_camera +tiny_p9_progress' \
firmware sim > build/spi_p4_ics55_iverilog_1119.log 2>&1
```
The active IHP130 Icarus replacement, explicitly authorized after its previous
attempt hit the outer timeout, is:
```sh
make CONFIG=configs/ci/ihp130-tiny.mk APP=ci_smoke SIMU=IVERILOG \
TINY_SPI_P4_ACCEPTANCE=YES BUILD_TIMESTAMP=2026-10-26-15-20 \
TINY_SIM_TIMEOUT=300000000 SOC_SIM_TIME=288000 \
TINY_SIM_ARGS='+tiny_spi_p4 +tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p10_camera +tiny_p9_progress' \
firmware sim > build/spi_p4_ihp130_iverilog_1520.log 2>&1
```
Both were launched with Bash background execution and `disable_timeout=true`;
their result commands invoke `vvp` directly with `+max_cycles=300000000`, not a
wall-timeout wrapper. Roots are
`build/ics55-tiny-2026-10-26-11-19-35b6184dae5c/` and
`build/ihp130-tiny-2026-10-26-15-20-995377fb20d0/`. Both have completed
naturally with `status=passed`, exit 0, `SIM_TEST_PASS Tiny cycles=53810943` and
zero forbidden markers. Wall times are 121321.334 s for ICS55 and 114295.959 s
for IHP130. Applying the accepted QUICK-A reduction (2710932 versus 43019427 A
cycles) to the 94425948-cycle full-A+B result gave a planning estimate of
54117453 cycles, not a measured verdict; the actual common Icarus cycle count is
53810943.
The ICS55 progress observer produced concrete log contamination, including
`sim.log` lines 639-645 (`SPI_P4_MEASURE`), the V22 records and the required
`SPI_P4_SD` record at lines 5433-5439. This is an observer/stream defect, not a
design-behavior verdict. The run finished naturally with zero forbidden markers,
panel `violations=0`, P9 38400/38400 words and raw full-size capture/SD values:
76800 pixels, 153600 bytes, 38400 words, 150 chunks/300 blocks, readback=1, FNV
`0xc198adc5`, a 143-pixel abort and result code 0. Those values occur in a mixed
progress/UART stream and are not intact line-oriented acceptance records.
The initial checker exited 1 with `ValueError` in `records()` while parsing the
split `SPI_P4_SD` record. Its traceback is retained at
`build/ics55-tiny-2026-10-26-11-19-35b6184dae5c/sim/iverilog/checker-stdout.log`.
The frozen contract constrains record content and independent oracle behavior,
not atomic stdout framing. The checker now consumes only complete, well-formed
`P9_TB_PROGRESS` records, including their newline, and preserves every other
character in order. Malformed progress is rejected before parsing, and malformed
SPI records produce checker problems rather than an uncaught exception. No raw
log text was edited or filtered, and every existing content/count/checksum check
remains active. Positive, corruption, malformed-observer and truncated-record
tests pass (13 P4 tests; 21 focused tests). Both full QUICK checkers exit 0 with
`problems=[]` and `status=passed`; records are under
`build/ics55-tiny-2026-10-26-11-19-35b6184dae5c/meta/spi-p4/check/record.json`
and `build/ihp130-tiny-2026-10-26-15-20-995377fb20d0/meta/spi-p4/check/record.json`.
IHP130 has the same observer interleaving and complete full-size B evidence.
Both legs are SIM PASS / CHECKER PASS; `phase_accepted` remains false. Future
progress-enabled acceptance should still prefer `+tiny_p9_monitor` with a
dedicated `+tiny_p9_monitor_log=` path to avoid the hazard at its source. The
executed checker commands are:
```sh
python3 scripts/spi_p4.py check \
--variant-root build/ics55-tiny-2026-10-26-11-19-35b6184dae5c --pdk ICS55 \
--quick --log build/ics55-tiny-2026-10-26-11-19-35b6184dae5c/sim/iverilog/sim.log
python3 scripts/spi_p4.py check \
--variant-root build/ihp130-tiny-2026-10-26-15-20-995377fb20d0 --pdk IHP130 \
--quick --log build/ihp130-tiny-2026-10-26-15-20-995377fb20d0/sim/iverilog/sim.log
```
The interrupted Icarus attempts are retained, not relabeled as hangs or failed
firmware:
| Profile / root | Result and boundary |
| --- | --- |
| ICS55 `build/ics55-tiny-2026-10-26-01-17-35b6184dae5c/` | `interrupted`, exit 130, 32376.440 s after the 32400 s outer launch/task timeout; empty buffered log, no hang proof |
| ICS55 `build/ics55-tiny-2026-10-26-10-19-35b6184dae5c/` | `interrupted`, exit 130, 3552.792 s; manually stopped to add progress visibility although healthy, an unnecessary interruption and not a design failure |
| IHP130 `build/ihp130-tiny-2026-10-26-04-43-995377fb20d0/` | `interrupted`, exit 130, 32378.289 s after the 32400 s outer launch/task timeout; empty buffered log, no hang proof; replaced by the authorized detached 15:20 run |
P3 compatibility was rerun with the standard 20000000-cycle budget:
```sh
make CONFIG=configs/ci/ics55-tiny.mk APP=ci_smoke TINY_SPI_P3_ACCEPTANCE=YES \
BUILD_TIMESTAMP=2026-10-26-01-19 TINY_SIM_TIMEOUT=20000000 \
firmware sim > build/spi_p4_p3_ics55_verilator_0119.log 2>&1
make CONFIG=configs/ci/ihp130-tiny.mk APP=ci_smoke TINY_SPI_P3_ACCEPTANCE=YES \
BUILD_TIMESTAMP=2026-10-26-01-20 TINY_SIM_TIMEOUT=20000000 \
firmware sim > build/spi_p4_p3_ihp130_verilator_0120.log 2>&1
```
Both PASS with `SIM_TEST_PASS Tiny cycles=1050629`, exit 0, and
`result-sim-check.json` passed with no rejected matches. Roots are
`build/ics55-tiny-2026-10-26-01-19-d1eafd9db70e/` and
`build/ihp130-tiny-2026-10-26-01-20-e29716f7754c/`. The measured increase from
the older 1037899-cycle reference is 12730 cycles; it is reported rather than
normalized away.
### Host, consumer and quality regressions
The full host suite was first run with `python3 -m pytest -q`: 2121 passed, 1
skipped in 4731.77 s (`build/spi_p4_full_host_pytest_recheck.log`). After the
lossless progress-reassembly repair, the complete suite was rerun: 2123 passed,
1 skipped in 5494.46 s
(`build/spi_p4_full_host_pytest_progress_reassembly.log`). After exact-abort and
panel-review closure, the final complete run reports 2124 passed, 1 skipped in
4771.54 s (`build/spi_p4_full_host_pytest_exact_abort.log`). The skip in each run
is the optional `pypdf` retrieval test. An earlier run had three failures caused
by the missing explicit block-top admission-output connection in
`tests/rtl/spi_test_body.svh`; that fixture repair preceded the passing rerun.
SPI-P1 recheck passed 52 tests in 59.65 s
(`build/spi_p1_recheck_0239.pytest.log`).
The final focused command and result are:
```sh
python3 -m pytest -q tests/test_spi_dma_admit.py tests/test_spi_p4.py \
tests/test_spi_p3.py tests/test_spi_register_parity.py \
--basetemp=build/spi-p4-exact-abort-focused
```
PASS: 22 tests in 42.81 s (`build/spi_p4_exact_abort_focused.pytest.log`). This
includes SPI-V12 admission/recovery, panel-oracle cases, positive/negative
progress reassembly, and exact abort-prefix coverage. The earlier 21-test result
is retained at `build/spi_p4_focused_progress_reassembly.pytest.log`, and the
20:05 focused-stage records remain under
`build/ics55-tiny-2026-10-25-20-05-35b6184dae5c/meta/spi-p4/`.
Affected-consumer commands and results:
```sh
python3 -m pytest -q tests/test_dma.py tests/test_ws2812.py \
tests/test_tiny_r2_p9.py::test_p9_dvp_dma_drain \
--basetemp=build/spi-dma-consumers-final
python3 -m pytest -q tests/test_xpi_io.py tests/test_dvp.py tests/test_gpio.py \
tests/test_tiny_r2_p6.py::test_dma_sdk_request_matrix \
tests/test_tiny_r2_p7.py::test_tiny_xpi_cdc_has_split_reset_endpoints \
tests/test_tiny_r2_p8.py --basetemp=build/spi-p4-consumers-0121
```
The first passes 11 tests in 127.01 s
(`build/spi_dma_consumers_final.pytest.log`); the second passes 22 in 26.86 s
(`build/spi_p4_consumers_0121.pytest.log`). Mini lint and DMA formal prove/cover
also pass in 131.497 s and 67.543 s under
`build/ihp130-2026-10-25-14-51-f1560e642e06/`. No dedicated executable
legacy-LCD/LVGL acceptance gate was found, so that compatibility remains a
residual gap; the XPI/DVP/GPIO tests are not relabeled as an LVGL acceptance run.
Final source rechecks pass: `ruff check .`,
`make BUILD_TIMESTAMP=2026-10-26-15-12 sw-host-test sw-format-check sw-policy-check`,
`make BUILD_TIMESTAMP=2026-10-26-15-13 rtl-format-check rtl-style-check`, and
`git diff --check`. The post-reassembly Ruff, focused 21-test and full host
results are listed above. These are mechanical checks, not complete MISRA
certification; no new MISRA deviation was needed. `check-rtl-lint` still fails
only because
`quality/warnings/ics55-tiny/rtl-lint.json` is absent. Actual Tiny lint has no
`UNOPTFLAT`, and no baseline was created or edited.
### Standalone synthesis and remaining gates
The fast block-level smoke used:
```sh
make CONFIG=configs/ci/ics55-tiny.mk SOC=TINY PDK=ICS55 HAVE_SVA=YES \
SIMU=VERILATOR SYNTH=YOSYS STA=OPENSTA JOBS=4 \
BUILD_TIMESTAMP=2026-10-26-02-39 spi-p1-synth
```
PASS under `build/ics55-tiny-2026-10-26-02-39-6a9ffe98980c/meta/spi-p1/synth/`:
`status=passed`, `phase_accepted=false`, balanced mapping at 41667 ps, 7439
cells, Liberty area 19286.12, two 256-bit payload FIFOs and zero SRAM macros.
The same synthesis command with `BUILD_TIMESTAMP=2026-10-26-01-18` also passed
under `build/ics55-tiny-2026-10-26-01-18-6a9ffe98980c/meta/spi-p1/synth/`.
These are standalone ICS55 block-synthesis results only. IHP130 block synthesis,
netlist simulation and STA were not run in this campaign; full synthesis,
netlist/STA and physical qualification remain deferred to SPI-P5.
Both Icarus A+B legs pass simulation and the full checker after lossless
progress-interruption reassembly, completing the four-simulator A+B matrix.
Icarus uses QUICK only for A geometry/delays, never for the 153600-byte B
workload. The observer hazard and separate-stream preference remain documented.
The other remaining gaps are full-A Icarus geometry, dedicated legacy-LCD/LVGL
acceptance, complete physical/timing/vendor/board/silicon qualification and human
review. `phase_accepted` remains false.
### Independent review closure (2026-10-28)
The read-only finalize review found one P1 and one P3 in verification
collateral. The P1 checker accepted any nonempty aborted prefix. It now requires
exactly 544 pixels for A window 7 and 143 for B window 11; zero and every other
nonzero prefix are rejected with explicit actual/expected messages. The positive
B fixture uses 143 rather than 1024, and new negative cases cover 0, 1, 400 and
1024 on both abort windows plus a cleared abort flag. A synthetic accepted-log
variant with 1024 B pixels fails with `window 11: abort pixels 1024 != 143`
(`build/spi_p4_wrong_abort_prefix.check.log`). All four original accepted logs
pass again with exact-length enforcement active.
The P3 fixture now covers complete-window odd pixel-byte count (violation 4)
and non-pixel-mode residual bits at CS rise (violation 1). Both simulators pass
`SIM_TEST_PASS ST7789_ORACLE partial_abort=2 residual_rejected=2
odd_pixel_rejected=1`; the production panel model is unchanged. The focused
suite passes 22 tests in 42.81 s (`build/spi_p4_exact_abort_focused.pytest.log`).
These fixes close the review findings without a long simulation rerun or any
verdict relaxation. `phase_accepted` remains false.
## SPI-P3 implementation checkpoint (2026-10-21)