RustyNES v2.6.19 — "Accession" (the DUT absorbs two releases of oracle behaviour, and the seed rule catches something for the first time)
Added
-
The FPGA core implements the OAM2 address counter, which did not exist.
sec_addr/sec_fetchwere combinational fromdotand served only as the
OAM-corruption seed: no 63/255/339 reset, no overflow flag, no dot-257 latch.
All three land, written from AccuracyCoin's own prose — a test ROM is
stimulus, not a reference implementation, and no third-party core was read
(ADR 0037 applies). There is ONE live flag,oam2_overflowed, and sprite
fetch reads it directly at all four read sites. An earlier draft of this
release latched it at dot 257 into a secondoam2_fetch_frozen, on the
reasoning that a wrap after 257 must not disturb a fetch already in progress
— and this entry described that design until after it had been published,
which is corrected here rather than quietly replaced. The latch is wrong
about the rule it implements: AccuracyCoin says rendering re-enabled ON OR
AFTER dot 256 leaves the fetch reading index 0, and a single sample at 257
misses every re-enable later than 257 — one at dot 260 found the flag clear
and fetched normally. It is also unnecessary once the increment window is the
32 even dots 258..320 rather than 33 from 256, because the counter can then no
longer wrap before the fetch window ENDS. Two defects, and the latch was
masking the other one.The counter is live and carried across scanlines and is not yet the read
pointer — the fetch still indexes by dot except when the flag forces index
0. That gap is this release's one declared divergence, and making the fetch
readoam2_fetch_addrdirectly is the remaining work. -
RustyNES.srf, the message-suppression file the MiSTer template ships and
the contributing wiki lists among a core's standard files. Four rules, one per
warning this design emits, each attributed — and deliberately none of
the template's three"*"wildcards. One of them blanket-suppresses ID
276020, "Inferred RAM node…", which is the message class that exposed both
v2.6.10's 128 KB of CHR in flip-flops and v2.6.6's M10K finding. Importing it
would blind the project to exactly the messages that have caught its two worst
synthesis defects.
Fixed
-
The DUT's dot-256 vertical increment acted on a mask change landing during
dot 256. v2.6.18 established the rule in the oracle — a$2001change taking
effect during dot N must not act on dot N — and the FPGA core had never seen
it. The increment was gated on the one-dotrenderingview; the two-dot view
already existed asreload_renderand was consumed only by the shift reload,
so the fix is one signal. AccuracyCoin on the DUT goes to 148 of 149, the
remainder beingMisaligned OAM2 Address. -
An overflow is an EVENT, and writing it as a STATE regressed two entries.
The second raise path — evaluation filling secondary OAM — was first written
as the levelsec_idx >= 32.sec_idxis cleared once a line, at the end of
the dot-1..64 clear, so once OAM2 fills the level stays true through dots 255,
256, 257 and 339: the dot-255 reset cleared the flag and dot 256 put it
straight back, so dot 257 latchedfrozenon every line carrying eight
sprites and every sprite fetch read OAM2[0].INC $4014andSprites On Scanline 0broke; the battery went from 2 differing entries to 3. Raised on
the increment that reaches 32 instead, both entries recover on the same run.
The one-minute sub-test said "both Pass" throughout — it was the instrument
incapable of seeing it, which is why the 134 M-cycle battery is the gate. -
A killed seed sweep reported a design failure, and could eat the
.qsf.
The snapshot lived in/tmp, which is tmpfs — so the event most likely to kill
the sweep can take the backup with it, and did: the trap never ran and the
working tree was left on a machine-writtenSEED. It now sits on real disk and
self-heals. Separately, a compile killed from outside was classified
COMPILE FAILED, a claim about the design; three outcomes sharing one exit
code are now separated by reading the log's own vocabulary. AndSEEDS=""
silently ran all five, because${SEEDS:-…}treats empty as unset. -
tb/quartus_clean.pyfailed every compile once the.srfexisted. Its
anti-vacuity guard read "no warnings at all" as "wrong file", which was right
in a world with no.srfand wrong in this one. The property it protects was
never "a warning exists" but "this log is a compile that ran", so it asks that
directly now — the four stages a--flow compilemust report — and still fails
on a truncated log, an abort, and any message citingrtl/ortb/. -
The browser build stopped opening the Netplay pane at you. Loading a ROM
force-opened "Netplay (browser)" on every wasm session. The force-open was
also the only route to the lobby, because the Netplay menu item was
cfg(not(target_arch = "wasm32"))— so removing it alone would have made the
feature unreachable rather than unobtrusive. There is now a wasm menu entry in
the same group with the sameWIFIglyph, enabled once a ROM is loaded, and a
source-shape gate pins both halves against each other.
Changed
-
The fitter seed is re-derived on v2.6.19's RTL and does not move — after
three sweeps were superseded.RustyNES.qsfrequires that every published
seed table describe one RTL, so v2.6.19's added registers supersede
v2.6.13's. Three tables preceded the one that stands:-
The first recompiled in place, so each seed was measured against the
residue of its predecessor's placement database. It reported that seed 1
fails setup by twelve picoseconds and does not close, and the conclusion
drawn — "the one-table-per-RTL rule has caught something for the first
time" — is retracted. Seed 1 closes. -
The second cleaned the database per seed and crossed midnight.
sys/build_id.tclis a pre-flow script that rewritesbuild_id.vat the
start of every compile andemu.svputsBUILD_DATEintoCONF_STR, so
the date is a constant in the design, not metadata — two compiles on
different days are different designs, which v2.6.15 had already measured
(pinning the date reproduced a published.rbfbyte for byte). The seed-1
run started at 23:54 and every other seed ran after midnight, which is why
seed 1's sweep row and its own shipping build disagreed. -
The third cleaned per seed and pinned the build date, and produced a
usable five-seed table — which three later commits in this same release
then superseded. Removing the dot-257 freeze latch and moving the DC
blocker'sFRACare RTL changes, and by this block's own rule an RTL
change replaces the design, so a table measured before them describes
something that no longer exists. Nothing flagged it; it was caught by
re-reading the rule against the commit log.
Re-swept on the final RTL — ten seeds, each from a clean database, all at
the same pinned build date260917:seed 1 2 3 4 5 6 7 8 9 10 setup +0.453 +0.439 +0.317 +0.267 +0.523 +0.269 +0.243 -0.008 +0.256 +0.311 hold +0.067 +0.098 +0.108 +0.105 +0.078 +0.086 +0.062 +0.098 +0.085 +0.078 The pin stays at 3, now holding the largest binding margin outright
(+0.108 ns) rather than a tie broken on setup. Two things the wider window
bought that five seeds could not:- Seed 8 does not close — setup -0.008 ns. This block has asserted since
v2.6.10 that full fitter effort "moves the whole distribution across zero
and the seed only picks where in it you land". That is false on this
RTL, and only the narrow 1-5 window made it look true. The distribution
is mostly positive, not entirely positive, and the pinned seed is therefore
load-bearing rather than merely preferred. - The third and fourth sweeps are a controlled comparison — same script,
same clean-per-seed discipline, the same pinned build date, differing only
in the three RTL commits. Every row moved; seed 3 alone went +0.611/+0.103
to +0.317/+0.108. That is the one-table-per-RTL rule demonstrated rather
than asserted — which is what this release's codename claims, and what its
first, contaminated attempt failed to earn.
What made every stale input findable rather than dismissable as noise is that
the build is deterministic: the shipping configuration produces a
byte-identical.rbfacross independent clean compiles. And the half that
generalises is not about Quartus — a measurement that confirms a rule you
are about to publish deserves the same scepticism as one that refutes it,
and a measurement stays current only until the thing it measured changes.
Every error here was invisible in any single run and obvious the moment two
runs were compared. -
-
What this release was verified against. The co-simulation ladder is
147 of 147, 0 failed, with no skipped rows. AccuracyCoin on the DUT is
148 of 149 —fail=0, coverage 149 of 149 entries executed on both sides
— and the single differing entry isMisaligned OAM2 Address, the one that
tests the read-pointer half above. Both were re-run on the FINAL RTL rather
than inherited from earlier in the release. The emulation core is unchanged,
so AccuracyCoin 144/144 and nestest 0-diff hold by construction. The
bitstream ships asRustyNES_20260917.rbf(seed 3, 4,018,912 bytes),
attached to the GitHub release on both repositories, and it is the one
built from the final RTL — an earlier staged copy predated three later
commits and was rebuilt before merging.No hardware has run it. The PPU gate compares the pre-palette index and
the APU gate per-channel integer levels, so the palette, the video timing
constants, the absolute audio level and its band-limiting sit downstream of
every gate, unverified by construction. -
cpu_interrupts_v2is ticked, three releases late.to-dos/mister/TASKS.md
read "DEFERRED — not started" whiledocs/mister.mdhad said since v2.6.15
that the five ROMs are verdict gates. Settled by running the ladder rather than
by reading either: all five pass,blargg verdict $00. Work already done and
never ticked, for the sixth recorded time in this programme.