Phosphoric › Artikelen › Phosphoric 2.0
Phosphoric 2.0: een cyclusgestuurde machine — en de claim die we intrekken
Wat we hadden gezegd en waarom het onjuist was, wat V2 veranderde, wat zichtbaar verandert — en wat we nog steeds niet claimen.
Tot 1.120.0-alpha presenteerde Phosphoric zich als „cycle-accurate”. Dat was niet waar in de zin die referentie-emulatoren aan dat woord geven. Dit artikel zegt wat is ingetrokken, wat in de plaats is gebouwd en waar de claim ophoudt. Namen van tests en opties zijn die van de repository.
1. Wat we hadden gezegd, en waarom het onjuist was
De 6502-kern voerde een instructie als één blok uit: de bustoegangen kwamen in de juiste volgorde en het totaal aantal cycli per opcode klopte, maar de interne cycli werden aan het einde van de instructie opgevuld, de NMOS-dummytoegangen bestonden niet, en interrupts werden op instructiegrenzen genomen. De VIA kreeg batches cycli, de ULA renderde een hele lijn in één keer, de PSG draaide op de audiobemonsteringsfrequentie.
Dat is een eerbaar niveau — we noemden het N2, „geordend op buscyclus” — maar het is niet
„cyclusexact”. We hebben de formulering ingetrokken, een verifieerbare schaal geschreven
(docs/ACCURACY.md: N1 tot N4, elk niveau gestaafd door de test die het bewijst), en een
automatische bewaker (make test-docs-claims) die elke ongekwalificeerde „cycle-accurate” in de
etalagedocumenten weigert. Daarna hebben we V2 gemaakt.
| Niveau | Naam | Operationele definitie |
|---|---|---|
| N1 | Geteld per instructie | Het totaal aantal cycli per opcode is exact; de periferie gaat na de instructie in batches vooruit. |
| N2 | Geordend op buscyclus | Elke echte bustoegang valt op de juiste cyclus binnen de instructie; interne cycli worden aan het einde opgevuld; IRQ op instructiegrenzen. |
| N3 | Stap voor stap per cyclus | De eenheid van vooruitgang is de cyclus: één busactie per cyclus (dummytoegangen inbegrepen), periferie in gelijke tred; IRQ/NMI op de voorlaatste cyclus. |
| N4 | Subcyclus (φ1/φ2) | De cyclus is onderverdeeld; setup/hold-races tussen kaarten en bus worden gemodelleerd. |
2. Wat V2 veranderde
Eerst een orakel
Vóór de kern werd aangeraakt speelt make test-cycle de SingleStepTests/65x02-vectoren af —
10 000 gevallen per opcode, met de verwachte busspoor cyclus per cyclus — en scoort vier eigenschappen apart
(eindtoestand, cyclustotaal, bussubsequentie, exacte bussequentie). Het gemeten en gepubliceerde vertrekpunt:
44,26 % exacte bussequenties. Het orakel bracht bovendien vijf logische fouten in de kern aan
het licht, verholpen nog vóór het begin.
Een micro-gesequencede kern
Elke instructie wordt een plan van micro-operaties, één per cyclus, die elk precies hun bustoegang doen —
inclusief de dummytoegangen (zero-page-indexering, paginaovergang, RMW-terugschrijven, dode stacklezingen).
Resultaat: 100,00 % over 2 440 000 gevallen. Interrupts worden bemonsterd op de
voorlaatste cyclus, wat gratis de vertraagde I-vlag van CLI/SEI/PLP
en het kapen van een BRK door een NMI oplevert. Beide kernen delen dezelfde berekening (vlaggen,
BCD, illegale opcodes): alleen de sequencing verschilt. De oude blijft beschikbaar (--cpu-legacy).
Een masterklok
emu_cycle() laat de hele machine één cyclus vooruitgaan, in een vaste volgorde:
de CPU doet zijn bustoegang, de periferie gaat één cyclus vooruit — nooit een batch —, dan fetcht de ULA de cel
van diezelfde cyclus. Dat is de volgorde die Mike Brown op de hardware heeft gemeten; tot 2.0.1 ging de ULA
eerst, en viel elke split één cel te ver naar rechts. De hoofdlus berekent niets meer: ze vraagt.
De componenten, één voor één
- VIA 6522: telt per cyclus; Timer 1 heeft zijn periode N+2 terug (het oude model gaf N: 20 % fout bij N=10).
- ULA: fetcht één cel van 6 pixels per cyclus, op het moment dat de straal ze leest — een schrijfactie midden in een lijn bereikt alleen de nog niet gescande cellen; rastersplits worden mogelijk.
- PSG AY-3-8910: draait op klok/8 (125 kHz) met geïntegreerde uitvoer — een toon boven Nyquist dempt in plaats van te vouwen; de envelop, van oudsher twee keer te traag, loopt op de juiste snelheid; de analoge uitgangstrap is overgenomen van het officiële schema.
- WD1793: meldt
LOST DATAen schrijfbeveiliging. - Cassette op signaalniveau: oneven framepariteit, niet even.
3. Wat zichtbaar verandert
- Rastersplits: een programma dat midden in een lijn inkt of modus wisselt krijgt wat de hardware zou geven, geen uniforme lijn.
- Geluid: enveloppen van de juiste duur, geen fantoomfluittoon meer op zeer hoge tonen, een gecentreerd signaal (gelijkstroom geblokkeerd zoals op de kaart).
- IRQ's: een interrupt kan niet meer vóór de lopende instructie worden genomen;
SEIbeschermt de volgende instructie niet tegen een al hangende IRQ. - Registers met destructieve lezing: een BASIC-
POKEnaar het dataregister van een ACIA verliest een byte, omdatSTA (zp),Yeen dummylezing doet vóór het schrijven — op de emulator zoals op de machine. Phosphoric was toleranter dan de hardware; dat is het niet meer. - Savestates: een toestand die midden in een frame is genomen hervat precies waar ze stopte (straalpositie, timers, interruptmonster).
4. Wat we onderweg hebben geleerd
Twee fouten zouden nooit zijn gezien zonder van methode te veranderen.
De PSG-envelop was „door herberekening” conform verklaard — een herberekening die 16 toestanden aannam in plaats van 32. Een onjuiste aanname is onzichtbaar bij herlezing; ze toont zich alleen door het signaal te meten. De audiotests meten nu frequenties en duren in plaats van bytes te vergelijken.
De tweede is nog leerzamer. Een niet-genomen sprong nam zijn beslissing één cyclus te laat, in een micro-op zonder bustoegang. De CPU-teller bleef juist, dus het orakel was 100 % groen. Maar de masterklok was één keer extra aangeroepen: de ULA ging een cyclus vooruit die noch de CPU noch de VIA had beleefd — ongeveer 410 keer per frame op de BASIC-ROM, ofwel één frame drift per seconde tussen het beeld en de rest van de machine. Een orakel dat alleen naar de CPU kijkt bewijst de synchronisatie van de machine niet. Wat het aan het licht bracht: een determinismetest van de savestates, die eiste dat rasterstops op exact dezelfde cyclus vielen.
5. Wat we niet zeggen
„Phosphoric is cyclusexact” — nee. De FDC wordt nog steeds getimed door vaste vertragingen op een plat beeld (geen MFM-stroom, dus geen echt byteverlies of CRC). De horizontale referentie is daarentegen geen conventie meer: de (gemeten) ULA-teller zet kolom 0 op count 0 — maar de absolute fase tussen die teller en de CPU is op een echte ORIC alleen waarneembaar met de „VSYNC hack”, die we niet emuleren. De halve cyclus van de VIA-one-shot is niet gemodelleerd. Het standaard laden van cassettes blijft de ROM-patch, uit keuze: dezelfde inhoud geladen, 2,4× minder cycli.
De exacte toegestane formulering, en de test die elke regel ervan zou laten vallen, staan in
docs/ACCURACY.md.
6. Kosten
De overstap naar de cyclus kostte, op de referentiemachine op volle snelheid, 491 → 611 µs per geëmuleerd
frame: 3 % van het budget van 20 ms. make test-bench weigert nu elke overschrijding
boven 5 %.
7. Sinds 2.0.0
- 2.0.1 — WebAssembly-build hersteld (kapot sinds de macOS-port), onlinepagina herbouwd in 2.0.
- 2.0.2 — intra-cyclusvolgorde CPU/ULA gecorrigeerd volgens de Unofficial ULA Guide van Mike Brown: de 6502 heeft eerst toegang, de ULA fetcht daarna dezelfde count; elke rastersplit viel één cel (6 pixels) te ver naar rechts. Het voorbehoud „horizontale referentie niet gekalibreerd” is opgeheven.
- 2.0.3 — hoofdlus opgedeeld in benoemde stappen (1 296 → 126 regels), geen zichtbare verandering.
- 2.0.4 — LOCI-co-simulatie: de F8-knop heeft nog één eigenaar (de mee-gesimuleerde firmware); lang indrukken = diagnostische ROM van Mike Brown.
Testsuite: 1 208 tests in 60 suites, 100 % groen; automatische release bij tag (Linux-binary, Windows-zip); browserversie online.
Bronnen & links
- Phosphoric-repository: Codeberg · Framagit · GitHub
- Nauwkeurigheidsschaal en status per component: docs/ACCURACY.md
- Oorspronkelijke technische nota (Frans): docs/articles/v2-cycle-stepped.md
- 6502-orakel: SingleStepTests/65x02; functionele test van Klaus Dormann.
- Mike Brown, ORIC 1/ATMOS Unofficial ULA Guide: oric.free.fr · oric.signal11.org.uk
- Online proberen: WebAssembly-versie