Releases: benedictemarty/Phosphoric
Release list
Phosphoric 2.1.1
Phosphoric 2.1.1
Phosphoric 2.0.4
[2.0.4] - 2026-09-12
Fixed — co-simulation LOCI : F8 faisait agir DEUX modèles à la fois (« Booting » figé)
Rapporté sous --loci-emu : booter la ROM de diagnostic (test108k) laissait
l'écran sur « Booting ». Le journal montrait la cause : à l'appui sur F8,
le modèle interne swappait la ROM hôte (menu locirom, ou test108k.rom
sur appui long), posait ses patches et reset le 6502 — et au relâchement
le firmware co-simulé recevait aussi le bouton (loci_emu_menu_button())
et armait son propre service ROM. Deux modèles répondaient au même bouton ;
sur appui long, la ROM de diagnostic chargée par l'un était aussitôt
remplacée par le menu servi par l'autre.
- Un seul propriétaire du bouton : sous
--loci-emu, F8 (GUI) et
loci-button(--control) ne touchent plus au modèle interne ; le
firmware traite l'appui — court = menu LOCI, long (≥ 2 s) = sa ROM de
diagnostic embarquée (EXT_BOOT_DIAG), puis reset du 6502 sur le vecteur
servi. Sans co-simulation, rien ne change. - Nouveau
loci_emu_diag_button()(Phosphoric) sur
emul_loci_diag_button()(~/loci/emul, commit d1626e0) : le maintien
de 2 s est simulé par un saut du TIMER du RP2040, pas par deux secondes de
firmware. - Vérifié headless (
--control, firmwarebuild-xip) : appui long → « Oric
Diag ROM V1.08k (C) 2023 Mike Brown — RAM Test Passed » ; appui court →
menu LOCI.make testsvert, buildLOCI_EMU=0(stubs complétés) OK.
Non résolu, faute de reproduction : le chemin « menu → rom: →
test108k → ESC ». Sous --loci-emu le sélecteur de fichiers est servi par
le firmware, dont la flash ne contient que basic11b/basic10/microdis.rom ;
d'où vient l'entrée test108k reste à établir. Et l'injection de touches
headless (--type-keys, natif ou HID) ne fait pas naviguer le menu co-simulé
(la ROM cesse de balayer le clavier après la première touche — préexistant,
identique en 2.0.0-alpha.7), ce qui empêche de scripter ce scénario.
EMU_VERSION 2.0.3 → 2.0.4.
Phosphoric 2.0.2
[2.0.2] - 2026-09-12
Fixed — ordre intra-cycle CPU/ULA inversé : chaque split raster tombait une cellule trop à droite
La « calibration horizontale de l'ULA » laissée ouverte en 2.0.0 est réglée par
la lecture d'une source mesurée, pas par une mesure nouvelle : le « ORIC
1/ATMOS Unofficial ULA Guide » 1.02 de Mike Brown (déconstruction de l'ULA
HCS10017, mesures à l'oscilloscope sur machine réelle, schéma reconstitué du
die en 2018).
Ce que dit la source
- Le compteur horizontal de l'ULA compte 0-63 à 1 MHz ; les colonnes 0-39
sont fetchées aux counts 0-39, le blanking occupe 40-63
(HBLANK = H5·(H4+H3)), l'impulsion de synchro les counts 49-52.
« Colonne 0 au cycle 0 de la ligne » n'était donc pas une convention de
l'émulateur : c'est le compteur du chip.--ula-fetch-offsetreste un outil
d'expérimentation, sa valeur juste est 0. - Dans le cycle, le 6502 accède d'abord, l'ULA ensuite : au front montant
de l'horloge 1 MHz le compteur s'incrémente et le 6502 fait son accès DRAM
(« it is asserting CAS here that performs the write ») ; puis « the ULA
access cycle begins » — le fetch de l'octet écran du même count, pendant
la moitié basse du cycle, la plus longue (d'où l'horloge asymétrique). - La phase absolue raster/CPU est inobservable sur un ORIC non modifié
(compteurs libres, reset asynchrone) ; elle n'existe qu'avec le VSYNC hack,
non émulé. Il n'y avait donc rien d'autre à calibrer.
Ce qui était faux
emu_cycle() faisait fetcher l'ULA avant l'accès du CPU : une écriture au
cycle c n'était vue qu'à c+1. Sur le matériel elle est vue par la cellule
c. Tout split raster était donc décalé d'une cellule (6 pixels) vers la
droite — et test_ula_reads_before_cpu_writes verrouillait ce comportement,
au nom d'une hypothèse (« l'ULA accède en φ1 ») que le guide contredit.
La correction
Ordre emu_cycle() : CPU → périphériques φ2 → fetch ULA du même count.
Test remplacé par test_cpu_write_visible_in_the_same_cell (STA sur la
cellule 13 au 14e cycle : la cellule 12 reste pleine, la 13 devient vide) —
rouge sur l'ancien ordre. test-raster-split, test-savestate-determinism
et le corpus (36 médias) inchangés ; make tests vert.
Documents alignés : docs/architecture/master-clock.md (ordre mesuré,
repère du compteur, phase absolue), docs/ACCURACY.md (ULA : « N3 pour le
fetch », la réserve « calage non calibré » retirée), README.md,
docs/articles/v2-cycle-stepped.md, CLAUDE.md.
Sources : http://oric.free.fr/HARDWARE/ula.html ·
https://oric.signal11.org.uk/html/ula1.htm
EMU_VERSION 2.0.1 → 2.0.2.
Phosphoric 2.0.1
[2.0.1] - 2026-09-11
Fixed — le build WebAssembly cassait depuis le port macOS ; page Pages en 2.0.0
serial_backend.cincluait<util.h>sous Emscripten (branche__unix__du
port macOS, 6398377) :make wasméchouait. Sous__EMSCRIPTEN__, pas de
pseudo-terminal (HAS_PTY 0).make wasmliaitloci_emu.c(émulateur RP2040 natif) dès que~/loci/emul
existait : le stub est désormais toujours utilisé en WebAssembly.- emsdk 6.0.9 installé, build reconstruit, gh-pages publiée sur les trois
forges avecshell.js(la page de juillet, antérieure à l'externalisation du
script, n'aurait plus fonctionné avec unphosphoric.htmlrécent).
https://benedictemarty.github.io/Phosphoric — vérifié :phosphoric.wasm
servi porte « 2.0.0 ».
EMU_VERSION 2.0.0 → 2.0.1.
Phosphoric 2.0.0 — la machine cadencée au cycle
Phosphoric 2.0.0 — la machine cadencée au cycle
Première version majeure. Ce qui change depuis la 1.x, et l'annonce qu'on retire, sont dans la note technique docs/articles/v2-cycle-stepped.md ; ce qui est exact et ce qui ne l'est pas, composant par composant, dans docs/ACCURACY.md.
- Cœur 6502 micro-séquencé : un accès bus par cycle, accès factices du NMOS compris — 100,00 % de séquence bus exacte sur les 2 440 000 cas de l'oracle SingleStepTests/65x02 ; interruptions échantillonnées au cycle pénultième.
- Horloge maître : un appel fait avancer toute la machine d'un cycle (ULA → CPU → périphériques), jamais à vide.
- VIA au cycle (période Timer 1 = N+2), ULA une cellule de 6 pixels par cycle (splits raster), PSG à horloge/8 (enveloppe corrigée, plus de repliement, étage de sortie relevé sur le schéma), WD1793 LOST DATA et protection en écriture, cassette parité impaire.
- Savestates : point de reprise exact, même pris en pleine trame ; les
.ost1.x se lisent toujours. - Non revendiqué : « exacte au cycle » pour la machine entière — le FDC reste cadencé par des délais forfaitaires, le calage horizontal de l'ULA n'est pas calibré contre du matériel.
Fichiers
phosphoric-2.0.0-linux-x86_64.tar.gz— binaire Linux x86_64 (SDL2 dynamique :libSDL2-2.0.so.0requis), docs incluses.phosphoric-2.0.0-windows-x86_64.zip—oric1-emu.exe+SDL2.dll+libwinpthread-1.dll(build MinGW du workflowwindows-build).
Les ROM ne sont pas distribuées : -r roms/basic11b.rom (Atmos) ou basic10.rom (ORIC-1).
La page WebAssembly (benedictemarty.github.io/Phosphoric) reste sur le build 1.49.0 pour l'instant.
v1.16.49-alpha — LOCI end-to-end complet
🎮 Highlights
Première release Phosphoric avec support LOCI complet de bout-en-bout. Premier émulateur grand public capable de charger automatiquement un jeu commercial Oric via le firmware LOCI ROM 0.3.0 et une image SD raw au format FAT16/FAT32.
✨ Nouveautés majeures (10 sprints)
| Sprint | Apport |
|---|---|
| 34an | Fix critique MIA spin window ABI — LOCI ROM boote, TUI navigable |
| 34ao | Backend SDIMG read FAT16/FAT32 (parser custom ~470 LOC, pas de FatFs) |
| 34ao+ | Intégration E2E : 5 bugs de plomberie corrigés (picker, MIA_BOOT, tape mount, ROM patches) |
| 34ap | Backend SDIMG write : alloc clusters, FAT mirror sync, dir entry CRUD |
| 34aq | Fix CSAVE TAP format byte-compatible avec format Oric canonique |
| 34ar | Review sénior : \$02B1 + SEC carry (Atmos "Errors found"), fd_kind[], mkstemp |
| 34as | MBR parser auto-detect + CSAVE source du staging buffer ROM |
| 34at | Fix CSAVE ORIC-1 : csave_end \$E80A + snapshot ZP avant mutation \$5F/\$60 |
| 34au | 7 ops LOCI stubbées implémentées (CPU_PHI2, OEM_CODEPAGE, STDIN_OPT, 5× MAP_TUNE_*) |
| 34av+ | Automatisation E2E LOCI : \e ESC matrix + flèches + doc TUI sodiumlb |
📊 Métriques
- 481 tests (vs ~330 à l'entrée du sprint 34an), 0 régression
- 34/36 ops LOCI implémentées (94%)
- ~3800 LOC production LOCI + ~3100 LOC tests + 238 LOC outil
- 0 modification du cœur CPU/mémoire/video (intégration en greffon I/O optionnel)
🎯 Validation E2E commercial
./oric1-emu -r roms/loci/locirom --loci --loci-sdimg loci_demo.img \\
--keyboard azerty \\
--type-keys '15000000:\\p3t\\p2 \\p2 \\p2\\e\\p9\\p1CLOAD""\\n\\p9\\p9\\p9'Charge automatiquement 007 "Dangereusement Vôtre" (DOMARK 1985) depuis l'image SD via le firmware LOCI. Écran final affiche le titre du jeu.
Voir `docs/CR/2026-06-07_E2E_LOCI_007_Tape_Loaded.md` pour le compte-rendu détaillé.
🛠️ Outil livré
- `tools/mkloci_sd` : populator FAT16 standalone (~240 LOC) — crée une image SD raw populée à partir de fichiers hôte, sans dépendre de mtools/mcopy.
📋 CLI nouveau
| Flag | Effet |
|---|---|
| `--loci` | Active le module LOCI MIA (bus $03A0-$03BF) |
| `--loci-flash DIR` | Sandbox POSIX comme stockage LOCI |
| `--loci-sdimg PATH` | Image SD raw FAT16/FAT32 comme stockage |
| `--type-keys CYCLES:\e...` | Auto-typing avec `\e` (ESC), `\u/\d/\l/\r` (flèches) |
| `--type-keys CYCLES:loci-hid:...` | Mode HID xram (défensif pour futures ROMs) |
🙏 Crédits
- sodiumlb : LOCI hardware + ROM + firmware + doc TUI (wiki)
- Ingé sénior : reviews v1.16.44 (Errors found via Oricutron .pch+.sym) et v1.16.46 (CSAVE ORIC-1 $E80A vs $E7FE)
- Oricutron : .pch et .sym de référence pour validation byte-pour-byte
📚 CRs détaillés (docs/CR/)
- `2026-06-07_LOCI_Fix_ABI_Closeout.md` — fix MIA spin ABI
- `2026-06-07_LOCI_SDimg_Backend.md` — backend read
- `2026-06-07_LOCI_SDimg_Write.md` — backend write
- `2026-06-07_Senior_Review_LOCI_SDIMG_CSAVE.md` — review architecture
- `2026-06-07_Senior_BASIC10_CSAVE_Investigation.md` — analyse Oric-1
- `2026-06-07_Senior_BASIC10_CSAVE_Followup.md` — preuves empiriques
- `2026-06-07_Senior_Putbyte_FF_Investigation.md` — hypothèse FF=ZP uninit
- `2026-06-07_E2E_LOCI_ROM_Boot_Observed.md` — baseline boot
- `2026-06-07_E2E_LOCI_007_Tape_Loaded.md` — E2E jeu commercial