docs(tiny): record R2-P9 validation and remaining gaps

Document the DVP integration contract, reviewed remediation and source-bound
ICS55/IHP130 evidence, preserving original phase IDs and historical runs.
Record matched firmware binaries, current functional results, observational
STA, warning deltas and unresolved global quality/qualification gaps.

Evidence was produced from 39ae718 plus the archived worktree; retain that
provenance rather than relabeling earlier runs with new commit identities.
P9 human acceptance remains pending. This documentation does not advance P10
or qualify a physical operating point.

Validation: read-only artifact/source hash review and git diff --check.
This commit is contained in:
maksyuki committed 2026-10-17 15:33:25 +08:00
1 parent 83fe263e40
commit 5b81dea4fe
2 files changed
+1887

No files matched your search

+316
View File
@@ -0,0 +1,316 @@
# Tiny R2-P9 DVP camera integration
This runbook records the Tiny R2-P9 DVP implementation at the source revision
that supplies the evidence. It uses the shared DVP V2 ABI at `0x1000E000`,
IRQ15, request `DVP_RX=11`, and Tiny DMA channel 2. GPIO12-23 ALT1 is the
exclusive camera profile; GPIO23 is the existing RCU CLKOUT/CAM_XCLK output.
The first workflow is a single snapshot into initialized XPI NSS1 PSRAM,
followed by complete readback and guard checks. RGB565 and YUV422 use exact
`2 * width * height` byte counts. Even active widths use DMA; odd widths use
the DVP RXDATA PIO helper. A successful frame requires DVP frame completion,
DMA completion with the exact byte count, drained destination responses and no
DVP, DMA or XPI error. The success path does not abort or flush the final FIFO
tail.
The deterministic camera model is `rtl/tiny/dv/tiny_dvp_camera.sv`. Its
dimensions, pixel pattern, PIXCLK loss and frame timing are recorded with each
run. Verification observers record accepted/delivered words, pending FIFO
high-water, longest backpressure and the tested service deadline. These values
are simulation observations, not hardware counters or a continuous-FPS claim.
Use the explicit profile commands below after generating the firmware and
filelists. Set `P9_MONITOR_LOG` to an absolute file in the selected new
variant's `meta/tiny-r2-p9/` evidence directory; create its parent first.
Use distinct files for separate attempts/profiles:
```sh
make CONFIG=configs/ci/ics55-tiny.mk APP=ci_smoke \
TINY_P9_ACCEPTANCE=YES SIMU=VERILATOR \
SOC_SIM_TIME=10800 TINY_SIM_TIMEOUT=40000000 \
TINY_SIM_ARGS="+tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p9_monitor +tiny_p9_monitor_log=${P9_MONITOR_LOG:?set an evidence log path}" firmware sim
make CONFIG=configs/ci/ihp130-tiny.mk APP=ci_smoke \
TINY_P9_ACCEPTANCE=YES SIMU=VERILATOR \
SOC_SIM_TIME=10800 TINY_SIM_TIMEOUT=40000000 \
TINY_SIM_ARGS="+tiny_psram +tiny_p9_camera +tiny_p9_half_ns=500 +tiny_p9_monitor +tiny_p9_monitor_log=${P9_MONITOR_LOG:?set an evidence log path}" firmware sim
```
`tiny_psram` populates the shared NSS1 device without enabling P8's workload
verdict. The legacy `tiny_p8_psram` still populates it and requires P8's four
performance windows and mapped-write evidence; keep that flag for P8 runs.
Both modes retain the shared active-CS timing check and `p8_absent` wiring.
Do not use `tiny_p8_psram` for P9 acceptance.
`tiny_p9_monitor` reports native-domain cumulative counters every 100000 REF
cycles without terminating the simulation. It is mutually exclusive with
`tiny_p9_diag*` and legacy serial-UART `tiny_p9_progress`. Diagnostic runs
stop early (including the 5000000-cycle guard) and cannot qualify a full
capture. The monitor reports camera VSYNC, DVP frame events and FIFO words,
DMA2 confirmed bytes/remaining/error, XPI handshakes/errors and CPU bus
completions. Samples carry their REF timestamps; they are not an atomic CDC
snapshot, retired-instruction count or physical measurement. XPI read counts
include boot NOR traffic; use interval deltas and frame readback for attribution.
Progress is written to the required `tiny_p9_monitor_log` file, never to the
character-stream UART console. Missing/unwritable log paths fail closed.
At the 1 MHz camera rate, QVGA VSYNC spacing is 153843 pixel clocks. A capture
armed around 107 ms cannot finish before approximately 308 ms; the old 172 ms
diagnostic window was insufficient. The 40000000-cycle/10800-second caps
reserve startup/frame alignment, capture, 12000000 cycles for full readback,
two further camera periods for PIO alignment/completion, and drain margin.
Readback is a planning allowance, not measured throughput. Run one explicit
profile once, retain any failure and diagnose before retrying; listing the
compatibility command above does not require another long replay. Keep one
fresh BUILD_TIMESTAMP through preparation, build and run and capture source
identity before compilation.
The full long-running Icarus Tiny firmware campaign remains deferred to the
final Tiny qualification phase. Focused DVP tests may run in both simulators;
full firmware results must retain command status, `TEST_STATUS`,
`SIM_TEST_PASS`, and the forbidden-error-marker scan. CPU-less focused benches
use command status, their explicit `SIM_TEST_PASS` and the same error scan;
they do not supply TEST_STATUS or replace firmware acceptance. UART text alone
is not acceptance evidence.
The short `tests/rtl/tiny_r2_p9_dma_tb.sv` fixture bypasses NOR boot and reuses
the production DVP/DMA blocks, including Tiny's actual DMA parameters. It
checks an even-width DMA frame, delayed final word/AXI response, late SLVERR,
odd-width PIO and consecutive toggle events. The sink is a controllable AXI
memory at an NSS1-window address, not the XPI controller or serial PSRAM.
Each simulator compiles once and reuses its executable for the SLVERR case:
The remediation adds a second backend using `apb4_xpi` and the pin-level
`ESP_PSRAM64H` model. It initializes the device through APB commands, writes
canaries through mapped AXI, captures a 16x8 RGB565 frame through the production
DVP and DMA2, then reads all 256 bytes and both canaries through serial PSRAM.
The shared fixture also checks a 7x3 PIO frame. The controlled backend retains
the delayed response/error and stopped-high/low pixel-clock recovery cases.
These benches bypass CPU boot, product pads, fabric and RCU; they are not a
full-SoC or physical result.
The top-level camera model now defaults to a 500 ns half-period (1 MHz input),
with `+tiny_p9_half_ns=<positive integer>` available for explicitly recorded
experiments. This is a candidate model rate, not a sensor qualification.
The external P6 codec drivers release GPIO15 (DIN loopback) and GPIO17
(audio reference) to high impedance when `+tiny_p9_camera` selects the camera
population. The audio oscillator/startup checks remain unchanged for other
workloads. GPIO ALT selection inside the SoC cannot disconnect these external
testbench drivers, so both board population and internal routing are required.
`tests/test_tiny_p9_pad_isolation.py` extracts the actual audio startup/drivers,
camera assignments and generated pad/DVP bindings into a small fixture. It
uses the production `tc_io_tri_full_pad` and `dvp_core`, with native ICS55 IO
in Icarus and the existing functional IO model in Verilator. Each backend
compiles once for an audio compatibility case, a 512-combination byte/audio
sweep, a 16x8 camera frame and negative legacy-driver collisions (combined
codec wiring and audio-clock-only injection). The frame
checks all 64 words and first word `0x02030001`. The fixture does not instantiate
the CPU, full GPIO controller, DMA, XPI or PSRAM, and does not qualify the
full-frame memory readback or physical pad timing.
Every frame uses byte `(column_byte + 3 * row) & 255`, independent of frame
sequence. The odd-width firmware case crops 7x3 from the same sensor geometry.
Firmware checks every payload word and guards. `tiny_p9_observers.svh` emits
separate `P9_OBSERVATION` records from real FIFO handshakes, including PIO
pops; firmware no longer prints zero-valued measurement placeholders.
`measurements()` parses records only; `validate_run()` additionally requires
successful command status, matching log digest and captured source/configuration
identity before a result can be accepted. Missing observations are an error.
The review follow-up adds same-configuration rearm, pending-control/armed RCU
admission, native reset confirmation and paired/repeated error-notification
cases to the same controlled binary. The native-reset fixture extracts the
actual global boot expression and generated DVP local-reset binding; it holds
other boot prerequisites satisfied. This checks independence from PIXCLK,
not a full-SoC boot session. The C MMIO model delays control application and
checks repeated Tiny/Mini DMA/PIO calls plus side-effect-free busy rejection.
The START/ABORT ordering follow-up reuses that binary with `+abort_order`,
`+abort_active` and `+abort_applied`. It checks stopped-high/low PIXCLK, an
in-flight START and a START queued behind W1C, repeated/coalesced commands,
the configuration application pipeline, and ABORT progress while an active
frame blocks a pending configuration. A subsequent START queued after ABORT
must still work. Each scenario checks that old requests cannot restart frame
events or leave FIFO payload, then verifies complete PIO readback after rearm.
These remain focused behavioral checks, separate from full firmware acceptance.
For firmware evidence, call `prepare_build()` before compilation into a new
variant, retain the before/after source snapshots and successful command
results, then call `capture_build()` to freeze ELF, HEX and simulator hashes.
`validate_run(..., build=...)` requires that build record, checks the current
artifact bytes, and matches the simulator and `+firmware=` launch paths. A new
source dictionary cannot relabel an old compiled artifact. A build record
without a passing simulation remains build evidence only.
```sh
PYTHONDONTWRITEBYTECODE=1 python3 -m pytest -q \
tests/test_dvp.py tests/test_tiny_r2_p9.py tests/test_tiny_r2_p9_evidence.py \
tests/test_tiny_r2_p6.py \
-k 'not p6 or dma_sdk_request_matrix or reset_and_macro_policy'
make sw-format-check sw-policy-check sw-host-test \
rtl-format-check rtl-style-check-all rtl-readiness-check-all
make CONFIG=configs/ci/ics55-tiny.mk APP=ci_smoke TINY_P9_ACCEPTANCE=YES \
BUILD_TIMESTAMP=2026-10-15-15-25 firmware
make CONFIG=configs/ci/ihp130-tiny.mk APP=ci_smoke TINY_P9_ACCEPTANCE=YES \
BUILD_TIMESTAMP=2026-10-15-15-25 firmware
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk ICS55 --dry-run
python3 scripts/regress.py --root . --suite pr --soc TINY --pdk IHP130 --dry-run
```
See the [verification ledger](tiny-soc-verification.md#p9-focused-integration-follow-up-2026-10-15-uncommitted-worktree)
for actual results, failed probes and remaining P9 acceptance gaps. These
focused tests do not qualify sensor rates or full camera-to-PSRAM transport.
The word-count correction uses a 32-bit counter and a 144-bit statistics
mailbox while preserving the V2 ABI, 512-byte FIFO and 128-bit configuration
channel. `tests/test_dvp_stats.py` checks real pixel input through the shared
DVP wrapper, CDC and APB at 65535, 65536 and 153600 words, including an
odd-width 65536-word frame, a stopped/resumed host clock and a subsequent
small frame. These CPU-less boundary tests do not replace the full VGA/YUV422
PSRAM campaign. Retain the earlier QVGA pass with its original source identity;
do not relabel it as a full-SoC pass for the widened statistics path.
Evidence belongs under `build/<profile>-<timestamp>-<config-hash>/meta/tiny-r2-p9/`.
Physical sensor, package, PVT, IO timing, PLL characterization and continuous
video qualification remain outside this phase.
## Row-size remediation
The source checks every complete row against the configured source width,
including rows outside a crop. The directed `+row_geometry` case sends
6+2 and 2+6 pixel rows for a 4x2 configuration, then short/long rows inside
and outside an 8x4 source's crop, in both wire formats. It checks SIZE and
the error IRQ, clears/rearms, and verifies a complete good PIO frame after
each of the twelve faults. Host tests separately reject SIZE even with
otherwise matching DMA/PIO completion counts on Tiny and Mini bindings.
The statistics fixture includes a legal 65535-pixel source row, odd-width
padding and full 640x480 capture.
This RTL change requires fresh synthesis and netlist-function evidence;
previous binaries/netlists remain tied to their original source. The approved
reduced follow-up runs RECOVERY and QVGA once per PDK and current-RTL full-size
focused tests. Earlier full-SoC VGA remains historical, not a new-source run.
See the verification ledger for actual command outcomes and open gates.
## Source-bound VGA/YUV422 campaign
`TINY_P9_WORKLOAD=VGA_YUV422` selects 640x480, format 1, 307200 pixels,
153600 words and 614400 bytes. The default QVGA_RGB565 and optional quick
path remain available; QUICK cannot be combined with VGA. The application
uses the existing SRAM-resident boot and initializes NSS1 PSRAM before writing
the frame at 0x54010000. It checks the exact HAL completion, every payload
word, both guards and XPI error state, then rearms for the existing 7x3 RGB565
PIO crop from the VGA sensor geometry. That second capture checks format
change/rearm and odd-row padding, not another full DMA frame.
The unchanged camera emits `(column_byte + 3 * row) & 255` at the selected
pixel clock. This is deterministic raw YUV422 byte transport, not sensor color
calibration or image-quality qualification. The parser requires the selected
format/geometry, exact WORD_COUNT/PIXEL_COUNT, zero XPI error, full readback,
guards, matching FIFO observations and the strict terminal verdict. The launch
must include the matching camera geometry and half-period; quick, stopped-clock
and early-stop diagnostics cannot qualify this workload.
The following entrypoint builds fresh artifacts and executes exactly once:
```sh
P9_STAMP="$(date +%Y-%m-%d-%H-%M)"
python3 scripts/tiny_r2_p9.py run \
--pdk ICS55 --workload VGA_YUV422 --timestamp "$P9_STAMP" \
--jobs 4 --pixel-half-ns 500 --max-cycles 160000000 --wall-timeout 43200
python3 scripts/tiny_r2_p9.py run \
--pdk IHP130 --workload VGA_YUV422 --timestamp "$P9_STAMP" \
--jobs 4 --pixel-half-ns 500 --max-cycles 160000000 --wall-timeout 43200
```
Each invocation selects its committed Tiny profile, SOC=TINY, explicit PDK,
APP=ci_smoke, TINY_P9_ACCEPTANCE=YES, TINY_P9_QUICK=NO, SIMU=VERILATOR and
SAFE24. It refuses an existing evidence directory or pre-existing build outputs.
After filelist/manifest generation it archives inputs before compilation,
captures ELF/HEX/model identities, then launches through run_flow.py with
durable result JSON and a separate passive progress log. Input and artifact
checks run again at completion. Tool executable hashes are retained; this
entrypoint does not claim a fresh verification of downloaded tool archives.
It does not retry a failure or accept the whole P9 phase.
Results are under the new variant's `meta/tiny-r2-p9/full-frame/`: source,
prepared-build.json, build-identity.json, tool-identity.json, launch.json,
console.log, progress.log, result-sim.json, result-sim-check.json,
bound-result.json and assessment.json. A running/interrupted record is not
a pass. Keep the timestamp and source unchanged throughout both campaigns.
At a 500 ns half-period VGA VSYNC spacing is 614883 pixel clocks, about
0.615 seconds. The limits above reserve multiple alignment/capture intervals,
complete serial readback and the PIO follow-up; they are execution ceilings,
not measured duration. A completely empty 512-byte FIFO would fill in about
512 microseconds at this byte rate without service. Use actual occupancy and
native-clock backpressure observations to report tested margins, not a
worst-case guarantee. Observe long-run progress every 30 minutes; preserve
and diagnose any failed attempt before deciding on another execution.
These runs do not replace current-source QVGA replay, the remaining P9
product-level error/recovery matrix, broader regression, synthesis/mapping,
netlist-function checks or physical qualification. Pre-final STA remains
observational. Full long Icarus stays deferred to final Tiny qualification.
## Remaining-acceptance campaign
`TINY_P9_WORKLOAD=RECOVERY` selects the new small validation application and
its own digest. The campaign uses `--workload RECOVERY`, adding
`+tiny_p9_small +tiny_p9_recovery`. The opt-in board observer consumes
`P9_CTRL` UART writes to select external camera/audio population and stop or
resume the camera model clock. It does not force DUT registers or internal
clocks. With recovery absent, existing camera/audio population behavior is
unchanged. The parser requires all seven cases, six validated captures and
IRQs, both stopped-clock rejection diagnostics, eight board controls and two
decoded audio sessions. The verification ledger records passing full firmware
executions on both PDKs, including the initial failed attempts and their
validation-firmware/observer corrections.
The new `netsim-dvp` target uses `app/asm/tiny_p9_netlist.S` to route GPIO
camera inputs, check the DVP ABI, capture 16x8 via PIO, verify all 64 words
and statistics, then write TEST_STATUS. It shares the mapped netlist with
`netsim-boot` but writes separate `netl/dvp/` logs and uses a 300000-cycle guard.
`TINY_P9_NETLIST_WALL_TIMEOUT` defaults to 10800 seconds for ICS55 and 7200
for IHP130, matching this campaign's explicit measured-speed budgets. The
original 1800-second IHP130 attempt timed out, while the identical compact image
passes a Verilator diagnostic in 177716 cycles. Mapped DVP completion is
recorded as passing for both PDKs in the verification ledger; this check does
not substitute for full frame DMA. Use `SIMU=IVERILOG SYNTH=NONE` for netlist simulation so ICS55
selects functional PDK models, retaining the same timestamp and synthesized
netlist. `SYNTH=YOSYS` is the synthesis-stage selection.
The new `+xpi_protection` focused case exposed a shared XPI first-error
event/metadata cycle mismatch in both simulators. The verification ledger
records the failure and the subsequent reviewed correction, followed by the
completed RECOVERY/QVGA, synthesis/netlist and observational STA campaign.
Keep
historical VGA evidence under its original identity and document the impact
of subsequent error-report-only RTL and opt-in board-control changes.
The `+service_budget +pixel_half_ns=500` controlled fixture exercises a
480-byte interval without consumer service and then checks every retained
word and the frame tail. At the pause boundary one word is still in the
source output register; it is verified after the external pixel clock
resumes, not misread from an empty FIFO. A second frame exceeds FIFO capacity
without service and must report overflow, followed by bounded cleanup.
The fixture reserves a conservative 16-byte margin for the source output
word, byte/pixel packing and clock-domain observation skew. No DMA buffering
is credited as extra FIFO capacity. The nominal empty-FIFO admission limit
is therefore 496 us at 1 MHz active input; the positive case uses 480 us.
This finite directed test and the full-frame high-water/backpressure records
support the selected no-contention model workload, not arbitrary competing
XPI traffic, a physical sensor rate, or a continuous-FPS guarantee.
The RECOVERY image is deliberately small (16x8 source with a nonzero 8x4
crop), preserving the original serial PSRAM model and full CPU/pad/fabric
path. Each profile uses one campaign invocation:
```sh
python3 scripts/tiny_r2_p9.py run --pdk ICS55 --workload RECOVERY --timestamp YYYY-MM-DD-HH-MM --jobs 4 --pixel-half-ns 500 --max-cycles 20000000 --wall-timeout 7200
python3 scripts/tiny_r2_p9.py run --pdk IHP130 --workload RECOVERY --timestamp YYYY-MM-DD-HH-MM --jobs 4 --pixel-half-ns 500 --max-cycles 20000000 --wall-timeout 7200
```
Replace the timestamp placeholder with one new concrete timestamp. This is
the accepted execution plan, not a statement that either run has passed;
the verification ledger and source-bound assessment own the actual verdict.
File diff suppressed because it is too large. Load diff