Aller au contenu
Phosphoricwiki
Sommaire

La précision, mot à mot

En septembre 2026, Phosphoric a retiré une annonce qu’il ne pouvait pas tenir. Il l’a remplacée par une échelle vérifiable, où chaque mot est adossé à un test qui le ferait tomber.

Dans cette page

Une annonce retirée

Jusqu’à la version 1.120, le projet se présentait comme « exact au cycle ». Un audit du 10 septembre 2026 a montré que ce n’était pas vrai au sens que les émulateurs de référence donnent à ce mot. Le cœur 6502 exécutait une instruction d’un bloc : les accès sortaient dans le bon ordre et le total de cycles était juste, mais les cycles internes étaient rattrapés en fin d’instruction, les accès factices n’existaient pas, et les interruptions étaient prises entre deux instructions. Le VIA recevait des paquets de cycles, l’ULA dessinait une ligne d’un coup, le PSG tournait au rythme de la sortie audio.

C’est un niveau honorable, que le projet a nommé N2. Mais ce n’est pas « exact au cycle ». Le projet a retiré la formulation, écrit une échelle, ajouté un garde-fou automatique, puis fait la version 2.0.

L’échelle

L'échelle de précision de Phosphoric, et qui est oùQuatre niveaux, du plus faible au plus fort. N1, compté à l'instruction : le total de cycles par instruction est juste. N2, ordonné au cycle bus : chaque accès tombe au bon cycle. N3, pas à pas au cycle : la machine avance d'un cycle à la fois, accès factices compris. N4, sous le cycle : les phases de l'horloge sont modélisées. Le CPU, les minuteries du VIA, la lecture de l'ULA et la cassette au signal sont au niveau N3 ; le contrôleur de disquette est N1+ ; le bus d'extension du LOCI est N4 partiel.Quatre niveaux, chacun prouvé par un testN1compté à l'instructionle total de cyclespar opcode est justeFDC WD1793 (N1+)N2ordonné au cycle buschaque accès au bon cycle,cycles internes rattrapésancien cœur(--cpu-legacy)N3pas à pas au cycleun cycle à la fois, accèsfactices comprisCPU 6502 (100 %)minuteries du VIAlecture de l'ULAcassette au signalN4sous le cyclephases φ1 et φ2,courses sur le busbus du LOCI (partiel)Le PSG, à part, est « cadencé au matériel » : horloge/8, sortie intégrée (docs/ACCURACY.md).
Quatre niveaux, du plus faible au plus fort, et le niveau atteint par chaque composant.
NiveauNomDéfinitionLe test qui le prouve
N1compté à l’instructionle total de cycles par opcode est juste ; les périphériques avancent par paquetscomparer les compteurs à la table officielle
N2ordonné au cycle buschaque accès réel tombe au bon cycle ; les cycles internes sont rattrapés ; IRQ aux frontièresobserver un registre à effet de bord
N3pas à pas au cyclela machine avance d’un cycle : un accès par cycle, accès factices compris ; tout avance en même temps ; IRQ au cycle pénultièmecomparer la trace du bus, cycle par cycle, à un oracle externe
N4sous le cyclele cycle est découpé en phases φ1 et φ2 ; les courses entre cartes et bus sont modéliséesun prédicat de course et des cas limites reproductibles

Chaque composant, à son niveau

ComposantNiveauCe qui manque
6502N3rien d’identifié : 100,00 % sur 2 440 000 cas ; seule divergence assumée, les 12 opcodes JAM arrêtent le processeur au lieu de bloquer le bus
VIA 6522N3 pour les minuteriesle demi-cycle du mode one-shot (N + 1,5)
ULAN3 pour la lecturela bordure et le blanking ; la phase absolue balayage/processeur ; les modes ULA-NG plein écran, rendus par ligne
PSGcadencé au matériella valeur du condensateur de couplage, illisible sur le schéma
WD1793N1+délais forfaitaires, image plate : pas de vraie perte d’octet ni de CRC
CassetteN3 au signalle défaut reste la ROM corrigée, par choix
Bus du LOCIN4 partielles constantes ne sont pas encore calibrées sur du matériel

Le VIA, mesuré sur un vrai 6522

Depuis la version 2.6.0, le comportement du VIA reprend six corrections mesurées sur un vrai 6522, reprises du projet Neo6502Vic20. Là-bas, elles ont été validées par 61 programmes de test VIC-20 sur 61, tirés de l’émulateur VICE, dont les résultats de référence viennent du matériel : décompte qui commence au cycle suivant l’écriture, one-shot rechargé, mode de T2 retardé, T2 sur 8 bits pour le registre à décalage, PB7 sans DDRB. Ces programmes ne tournent pas encore dans la CI de Phosphoric ; les règles y sont verrouillées par make test-io.

La version 2.7.0 a ajouté un chemin paresseux exact : un cycle où rien ne peut arriver est seulement compté, puis appliqué d’un bloc avant le prochain accès. Le comportement reste celui du pas à pas : make test-via-lazy rejoue 116 lignes de commande contre une construction sans ce chemin, sans aucun écart. Le gain est de 20 à 30 %.

Les mots permis, les mots refusés

FormulationStatut
« cœur CPU exact au cycle »✅ depuis la 1.124 : 100 % de séquence bus exacte, interruptions au cycle pénultième
« machine cadencée au cycle »✅ depuis la 2.0.0-alpha.8 : l’horloge maître fait avancer tout, jamais à vide, et une sauvegarde d’état est un point de reprise exact
« précis au cycle bus » pour la machine entière✅
« compteurs de cycles exacts par opcode (256/256) »✅
« exact au cycle » seul, pour la machine entière❌ le contrôleur de disquette est N1+, le demi-cycle du VIA et la phase absolue ne sont pas modélisés
« WD1793 exact au cycle »❌ dire « WD1793 cadencé en cycles, modèle image plate »

Le garde-fou make test-docs-claims refuse toute formulation non qualifiée dans les documents de vitrine du dépôt. Ce wiki suit la même règle.

Les accès factices touchent les registres

C’est la conséquence la plus surprenante du niveau N3, et elle est voulue : un cycle factice est un vrai cycle de bus, et une puce ne sait pas qu’il est factice.

L'accès factice qui mange un octetLe POKE du BASIC écrit avec STA (zp),Y. En six cycles, le 6502 NMOS lit l'opcode, l'adresse de page zéro, puis le pointeur, puis fait une lecture factice de l'adresse visée avant d'y écrire. Si l'adresse est le registre de données d'un ACIA, cette lecture consomme l'octet reçu : un programme d'écho en BASIC perd des octets, sur la vraie machine comme dans Phosphoric depuis la 2.0.POKE 1021,C vers le registre de données d'un ACIASTA ($zp),Y : 6 cycles, 6 accès au buscycle 1R PClit l'opcode$91cycle 2R PC+1lit l'adressede page zérocycle 3R zplit le pointeur(octet bas)cycle 4R zp+1lit le pointeur(octet haut)cycle 5R $03FDlecture facticede l'adresse viséecycle 6W $03FDl'écriturevouluel'octet reçu est consommé iciUn cycle factice est un vrai cycle de bus : la puce ne sait pas qu'il est factice.Avant la 2.0, Phosphoric n'émettait pas ces accès : il était plus permissif que le matériel.Pilote série : écrire en assembleur, avec STA absolu (sans cycle factice).
Le POKE du BASIC fait une lecture factice avant d’écrire : sur un ACIA, elle mange l’octet reçu.

Les mêmes précautions valent pour tout registre à lecture destructive : ACIA 6551 et 6850, registres de FIFO. Avant la 2.0, Phosphoric n’émettait pas ces accès : il était plus permissif que le matériel.

Ce qu’on a appris en route

Deux défauts n’auraient pas été vus sans changer de méthode :

  1. L’enveloppe du PSG, déclarée conforme par un recalcul qui supposait 16 états au lieu de 32. Une hypothèse fausse ne se voit pas à la relecture, seulement en mesurant le signal.
  2. Le cycle fantôme d’un branchement non pris. L’oracle du processeur était vert à 100 %, mais l’horloge maître était appelée une fois de trop, environ 410 fois par trame. Un oracle qui ne regarde que le processeur ne prouve pas la synchronisation de la machine. C’est un test de déterminisme des sauvegardes d’état qui l’a révélé.

Le coût

Le passage au cycle a coûté, sur la machine de référence à pleine vitesse, de 491 à 611 µs par trame émulée : 3 % du budget de 20 ms. make test-bench refuse désormais tout dépassement de 5 % de ce budget.

Les audits de fiches techniques

En plus de l’échelle, le dépôt tient un audit de conformité aux fiches techniques (docs/HARDWARE_CONFORMANCE.md) : chaque cœur est relu ligne à ligne contre la fiche du constructeur. Chaque écart est classé corrigé (avec son test) ou déviation assumée (avec sa raison). Par exemple, pour le WD1793 : Read Address écrivait le mauvais octet dans le registre de secteur ; les commandes de pas ignoraient le drapeau de mise à jour de piste ; Force Interrupt levait toujours une interruption, alors que seule la variante D8 le fait. Tous trois sont corrigés.

Sources dans le dépôt : docs/ACCURACY.md, docs/articles/v2-cycle-stepped.md, docs/specs/V2_CYCLE_ACCURACY.md, docs/HARDWARE_CONFORMANCE.md.