# CPU cache return compatibility

Run the maintained regression against current RTL:

```sh
python3 tests/cpu-compat/run.py --log build/cpu-compat/regression.log
```

An optional `--rtl path/to/Minimig1.v` tests a private candidate. The runner
freezes inputs and records SHA-256 hashes, then requires:

- 24 PiStorm cases / 3,072 successful reads on the candidate.
- Four exact R4 controls / 512 reads, including 64 expected cached-return
  failures with every pre-release S6 sample correct.
- Six selector-transition cases / 126 accesses: hit to miss, uncached read,
  both byte writes, normal mode, reset/host invalidation, idle bypass, and
  bypass withdrawal during an acknowledged hit. Source/payload hold and
  unchanged classification timing are asserted. AS gaps are 1/16/17/20/35/140 ns.
- Five two-way bypass cases / 75 accesses, restoring eligibility 0.1/4/8/12/20 ns
  after the selector-clearing edge. Correct data and at least half a CPU
  cycle from restored source selection to ACK are required. Subsequent
  cached and uncached transactions are also checked.
- Three guarded RTL mutations reproduce the first v2 behavior, removal of
  the output ACK guard, and removal of the registered ACK qualification.
  Each must fail on its specific data/ACK-ordering assertion. The runner
  requires each mutation to match exactly once and records its source hash.
- A separately identified exact-R4 1 ns AS-gap stale-data control; R7 must pass
  that logical schedule without claiming physical pulse-width qualification.

The production fix must pass the candidate cases; the R4 failure is an
explicit negative control, not an accepted candidate corruption.

## Actual adapter source and license

`pistorm_reference.v` is **unmodified** PiStorm CPLD RTL, retaining Claude
Schwarz and Niklas Ekström's copyright notices. Its MIT license is included
as [LICENSE.pistorm](LICENSE.pistorm).

Provenance:

- AmiCube reference commit `0ef2e8f1ed240b5ec13b0dc8e30b88aab959d790`,
  `fpga/hard_accel_h9/tests/pistorm.v`.
- Independently verified byte-for-byte against `pistorm-main/rtl/pistorm.v`
  in [the archived PiStorm source](https://www.minimig.ca/software/pistorm-main.zip).
  Its accompanying `pistorm-main/LICENSE` was copied verbatim.
- Archive SHA-256:
  `06ab4e748c8699b6f08aa43da7ab86a91c0fadfd106aa2373cd9d8ae34df332e`.
- CPLD RTL SHA-256:
  `884a8cd317a890c25907d3081d126e80d1b6854b5df180635ec69de361bab256`.
- R4 control commit `00464da53412984bdcecba9a4c4c5afcbd3de6dd`,
  `Minimig1.v` SHA-256:
  `0e89780792b82780bd90a1ca621119f8f93f384ad5024acbcdb145e24b6968bd`.

No network access is needed to run the tests. The pinned adapter and R4
hashes are checked before simulation. This adapter model does not establish
which CPLD firmware is fitted to the user's hardware, and is not a TF030 model.

## Model assumptions and isolation

The actual CPLD runs its GPIO side at 200 MHz and its socket state machine
from the forwarded CPU clock. The bench models its external address, write,
and transparent read latches. Both read latches open in S7 as AS rises.
A weak keeper remembers the last driven bus value; it does not fight a
driving device. GPIO register writes use 40 ns setup/high/low intervals.

The chipset clock is 7.094 MHz, with real Q0/Q1/Q2/Q3 relationships to
28.375 MHz. Normal mode uses its complementary clock; turbo uses 60.297 MHz.
The CPU-clock pad delay is 5 ns and DTACK delay is 3 ns. Turbo phases are
0/8/16 ns. These are functional timing assumptions, **not measured fitted
board timing or an electrical qualification**.

Independent data/OE delays in nanoseconds are `(0,0)`, `(2,10)`, `(10,2)`,
`(2,2)`, `(5,10)`, `(10,5)`. The 2/10 and 10/2 cases come from the reference
repository's existing PiStorm test. Equal/zero-delay cases establish controls;
the 5 ns cases check whether the failure follows relative path order.

Only the bridge's final tri-state assignment is instrumented in a temporary
source copy, splitting its **unchanged** data expression and OE expression
into separately delayed wires. Internal bridge/cache logic is untouched.
The exact instrumented source hash is recorded. The bench uses a deterministic
ROM/slow-memory function, a 20 ns read delay after Q1, and a distinct idle
mux word outside reads. The backing word persists for 1 ns after clk28 Q0
so the related clk7 register can capture it. This explicit functional hold
assumption does not establish routed setup/hold margins. It does not model
full SRAM, DMA, or analogue decay.

Each case reads 128 words/bytes: ROM and slow-bank misses/hits, adjacent
indices, both byte lanes, and same-index tag replacement. Every S6 sample is
checked **before** AS release, giving a normal MC68000 sample-point control
inside each PiStorm transaction. Actual PiStorm S7 latch contents are checked
separately. This is not a separate full MC68000 instruction model.

## Established result and narrow fix

R4 passes all 3,072 S6 samples, yet returns the idle mux word on 384 cached
S7 captures across six turbo cases where data changes before OE disables.
Normal mode and the opposite/equal delay order pass. The full R4 diagnostic is:

```sh
python3 tests/cpu-compat/run_pistorm_release.py \
  --rtl path/to/exact-r4-Minimig1.v --expect-release-failure \
  --log build/cpu-compat/r4-release-matrix.log
```

The initial v2 selector fix registers `cache_data_selected` at the existing
classification edge, retains it through AS-high, and clears it on an
ineligible active request. Data and ACK capture stages are unchanged. Its
24-case matrix passes every S6 and S7 sample, both in the private candidate
and after integration into R5 source. This isolates the response
selection race; it does not prove all PiStorm boot problems are solved.

Independent review found a second corner in v2: if bypass is asserted and
removed within the same AS-low epoch, the selector clears but cannot restore,
while cached ACK reasserts. The data bus can then carry the fallback word.
The v3 revision restores the selector from the completed lookup decision,
qualifies output ACK with that selector, and also samples the selector in
the registered ACK stage. The first guard prevents stale ACK from reappearing
while data is deselected; the second retains the normal half-cycle data lead
when selection is restored. Ordinary lookup/ACK timing is unchanged.

The bypass bench drives `blk` directly to isolate this state-machine corner;
it does not simulate the SPI commands or claim the offset sweep describes
actual OSD command timing. The `v2-behavior` negative is a guarded mutation
of the frozen current source, not a byte-for-byte historical bitstream or
RTL snapshot. The separate R4 control remains the exact published source.

## Historical short-AS-gap control

The logical transition bench can assert a new request after only 1 ns of
AS-high. R4 and the R5 held-source fix corrupted the next cached word in this
schedule: the old refill sampler could miss the short idle pulse and use the
next live bus value. That historical defect is distinct from the S7 selector
race. The exact R4 negative control remains pinned and must still reproduce it.

## R7 recorded-response regression

R7 also records uncached read data and refills read cache lines before external
ACK. The 24 PiStorm cases remain required to pass. The logical 1 ns AS-gap
selector test now passes all 21 accesses; the exact R4 source still fails its
original stale-data control. This changed expectation does not qualify a 1 ns
physical AS pulse or reset-recovery timing. Six selector cases cover 126
accesses. The original five gap cases and the bypass guard mutations remain.
