Dokumentation › SEDORIC
SEDORIC-Diskettenformat & Werkzeuge
Primäre Referenz: das SEDORIC 3.0-Handbuch (sedna3_0.pdf), abgeglichen mit
„SEDORIC 3.0 à NU“ von A. Chéramy und den Werkzeugen des SCUMM-Oric- / scoop-oric-Projekts. Nichts ist
erfunden: Die folgenden Offsets sind die des Handbuchs, byte-exakt gegen den Deskriptor-Dump verifiziert, den das
Handbuch selbst als Beispiel angibt.
1. MFM_DISK-Container
256-Byte-Header: "MFM_DISK" + sides (u32 LE) + tracks (u32 LE) + geometry
(u32 LE). Dann ein Track-Block von 6400 B pro (Seite, Track), in SIDE-MAJOR-Reihenfolge:
alle Tracks von Seite 0, dann alle von Seite 1 (Block = side * tracks + track).
Jeder Track-Block: Anfangs-Gap 60×$4E, dann pro Sektor
12×$00 | A1 A1 A1 FE [trk side sec size] CRC | 22×$4E | 12×$00 | A1 A1 A1 FB [256 data] CRC | 38×$4E,
$4E-Auffüllung bis 6400 B. CRC-16/CCITT (poly $1021, init $FFFF) über die 4
Markerbytes + die Daten.
Ein RAW-Image (256-Byte-Sektoren aneinandergereiht, dieselbe Side-Major-Reihenfolge, ohne Rahmung)
wird von sedoric-info akzeptiert und von oric1-emu --disk-create /
tools/sedoric_inject.py erzeugt. tools/dsk_raw2mfm.py konvertiert RAW → MFM_DISK.
2. Systemsektoren (Track 20)
| Sektor | Rolle | Schlüsselfelder |
|---|---|---|
| s1 System | Diskettenname + Autoexec | +9..+29 Diskettenname (21 B) · +0x1E..+0x59 INIST (60 B: ASCII-Boot-Befehle, getrennt durch :, abgeschlossen mit #00) |
| s2 VTOC/Bitmap | Zähler | +2,+3 freie Sektoren (LE) · +4,+5 Dateizahl (LE) |
| s4 Directory | Katalog | +0,+1 Link zum nächsten Dir-Sektor (0=Ende) · +2 High-Water-Mark · 16-Byte-Einträge ab +16 |
Directory-Eintrag (16 B): name[9] ext[3] track sector
nsec status (V4 gültige Datei = $40; Bit 7 = gelöscht).
Hinweis (auf Master-Disketten beobachtet): Der VTOC-free/files-Zähler kann eine
80-Track-Vorlage sein, die auf ein kleineres physisches Image gestempelt wurde — eine Vorlage, kein neu
berechneter Zustand. sedoric-info meldet daher sowohl den VTOC-Zähler als auch die Zahl der tatsächlich im
Katalog durchlaufenen Dateien.
3. Dateideskriptor-Sektor
Vom Directory-Eintrag angezeigt (track,sector). Echter Dump aus dem
Handbuch (Deskriptor der BANQUE-#7-Systemdatei, S.16):
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 00 FF 40 00 C4 FF C7 00 00 04 00 05 0B 05 0C 05 0D 05 0E 00 00
| Offset | Feld | Beispiel |
|---|---|---|
+0,+1 | Link zum nächsten Deskriptor (00 00 = keiner) | 00 00 |
+2 | Erst-Deskriptor-Marker | FF |
+3 | Typ: b0=AUTO, b6=Datenblock, b7=BASIC → $40=ML, $41=AUTO ML | 40 |
+4,+5 | Ladeadresse (LE) | 00 C4 = $C400 |
+6,+7 | Endadresse (LE) | FF C7 = $C7FF |
+8,+9 | Ausführungsadresse, falls AUTO (LE) | 00 00 |
+0xA,+0xB | Anzahl der Datensektoren (LE) | 04 00 = 4 |
+0xC.. | Datensektorkarte (track,sector)×n, abgeschlossen 00 00 | 05 0B 05 0C 05 0D 05 0E 00 00 |
Dieser Dump korrigiert die alte tap2sedoric-Implementierung, die +3=0 ließ
(kein Typ) und die Sektorzahl bei +9,+10 in Big-Endian schrieb (überlappend mit der
Ausführungsadresse). Korrigiert seit v1.64.0.
Verkettete Deskriptoren (Dateien > 122 Sektoren) — validiert
Ein Deskriptor-Sektor enthält nur einen Teil der Karte: Der 1. Deskriptor trägt den Header (12 B)
und dann die Karte ab +0x0C (122 Paare max, 0x0C..0xFE); jeder folgende
Deskriptor trägt nur den Link +0,+1 und dann die Karte ab +0x02 (127
Paare max). Der Link +0,+1 zeigt auf den nächsten Deskriptor (00 00 = letzter).
+0xA,+0xB (1. Deskriptor) = Gesamtzahl der Datensektoren. In situ
validiert: eine Datei mit 150 Sektoren (2 Deskriptoren) vollständig von LOAD geladen.
tap2sedoric und sedoric_inject.py verketten seit v1.65.0.
4. Werkzeuge
| Werkzeug | Rolle |
|---|---|
tap2sedoric <in.tap> -o out.dsk -b base.dsk [-n NAME.EXT] [-a] [-e EXEC] [-i "INIST"] | injiziert eine CSAVE-.tap in eine MFM-Sedoric-Diskette (Datei + konformer Deskriptor + Dir-Eintrag + VTOC; -a/-e AUTO, -i Boot-Autoexec) |
sedoric-info <disk.dsk> [--check FREE:FILES] | inspiziert VTOC, Diskettenname, INIST, Katalog und decodierte Deskriptoren; --check = Regressionswächter für die Zähler |
tools/sedoric_inject.py … | RAW-Injektion (direkte Offsets) |
tools/dsk_raw2mfm.py <raw> <out.dsk> … | RAW → MFM_DISK (Side-Major-Blöcke) |
Typische RAW-Kette: oric1-emu --disk-create base.raw (dann INIT beim Booten für eine echte VTOC) →
sedoric_inject.py → dsk_raw2mfm.py → oric1-emu --disk-rom microdis.rom -d.
5. Multi-Datei-Injektion (Grenze aufgehoben)
Historisch allozierten sowohl tap2sedoric als auch sedoric_inject.py stets
ab Track 21 Sektor 1, ohne die bereits belegten Sektoren zu berücksichtigen: Eine zweite Injektion auf dieselbe
Diskette überschrieb die erste.
Seit v1.64.0 durchlaufen beide Werkzeuge den Katalog (vollständige Kette) und die Sektorkarten der
vorhandenen Deskriptoren — einschließlich der verketteten Katalogsektoren selbst — um belegte
Sektoren vor dem Allozieren zu markieren. Verifiziert durch make test-sedoric-tools.
Directory-Sektor-Verkettung (implementiert)
Wenn der aktuelle Katalogsektor voll ist (15 Einträge), durchlaufen die Werkzeuge die Kette über den
Link +0,+1; ist die gesamte Kette voll, allozieren sie einen freien Sektor, initialisieren ihn als
leeren Katalog und verketten ihn. Da Katalogsektoren per Track/Sektor-Link lokalisiert werden, kann ein
verketteter Katalog auf jedem freien Sektor liegen. In situ validiert.
6. Eine Maschinencode-Datei unter Sedoric ausführen (in situ validiertes Rezept)
Laden/Ausführen im Emulator verifiziert (Bare-Boot + LOAD). Angetroffene Fallstricke und gelöst:
| Befehl / Fall | Ergebnis |
|---|---|
PROBE tippen (nackter Name) bei Ready | ?SYNTAX ERROR — ein nackter Name startet nur ein AUTO-BASIC |
LOADM"PROBE" | ?TYPE MISMATCH — LOADM ist der Kassetten-ROM-Befehl |
CLOAD"PROBE" | kein Fehler, aber lädt nichts (BASIC-Dateien) |
LOAD"PROBE" bei .BIN | ?FILE NOT FOUND — .COM ist die Standarderweiterung |
LOAD"PROBE",J bei AUTO | BREAK ON BYTE #5000 — ,J kollidiert mit der AUTO-Flag |
LOAD"PROBE" bei .COM AUTO (Typ $41) | lädt UND führt aus ✅ |
Rezept: als .COM AUTO injizieren (tap2sedoric … -n NAME.COM -a -e EXEC),
dann bei Ready: LOAD"NAME". Der Sedoric-Befehl ist LOAD
(erkennt BASIC vs. binär automatisch über das Typbyte +3), mit Optionen ,A (Adresse) und
,J (Sprung).
Nackter bootfähiger Sedoric-Master (deterministisch)
Um eine selbstgemachte .COM zu validieren, braucht man eine Diskette, die ohne konkurrierende Anwendung
nach Ready bootet. Robuste, timing-freie Methode:
tools/sedoric_mkbare.py disks/SEDO40u.DSK bare.dsk # neutralisiert die INIST
tools/sedoric_mkbare.py disks/SEDO40u.DSK auto.dsk 'LOAD"PROBE"' # oder Auto-Start
Es neutralisiert (oder ersetzt) die INIST (Track 20 Sektor 1, +0x1E..+0x59,
MFM-Sektor-CRC neu berechnet; RAW ebenfalls behandelt) → die Diskette fällt auf ein nacktes SEDORIC V4.0 /
Ready zurück, bleibt aber bootfähig.
Eine Datei aus Maschinencode laden (in situ validiertes Rezept)
Aus einem laufenden ML-Programm (von LOAD gestartet) ist das Sedoric-RAM-Overlay nicht
gemappt: die DOS-Routinen direkt aufzurufen ($DB2D Suche, $E0EA Lesen)
stürzt ab. Der robuste Weg führt über den „!“-Vektor $0467 (im niedrigen
RAM, immer gemappt), der zum Overlay umschaltet, den SEDORIC-Interpreter ($D3AE) auf der von
TXTPTR ($00E9/$00EA) angezeigten Zeile ausführt und dann zurückschaltet und RTS
macht.
LDA #<CMD : STA $E9 ; TXTPTR = Adresse der Befehlszeile
LDA #>CMD : STA $EA
JSR $0467 ; "!"-Vektor: fuehrt den Befehl aus (Overlay geregelt)
; ... Datei geladen; normale Fortsetzung ...
RTS
CMD: .byte "LOAD\"SCDATA\"", 0 ; SEDORIC-Zeile mit $00 abgeschlossen
Fallstrick: Die Zeile muss mit $00 abgeschlossen werden,
niemals mit CR ($0D). Mit CR schließt der $D3AE-Interpreter nicht ab und macht
kein RTS. TXTPTR zeigt auf das erste Zeichen (das L).
Sedoric-RAM-Overlay ↔ BASIC-ROM-Umschaltung (validiert)
Aus einem von LOAD gestarteten ML-Programm ist das BASIC-ROM bei $C000-$FFFF gemappt:
Systemvariablen und Routinen liegen im Overlay → vor jedem $C000+-Zugriff
umschalten. Am einfachsten: JSR $0477 (Sedoric-Stub im niedrigen RAM) — ein
ROM↔Overlay-Toggle, der Laufwerk/Seite/IRQ über den $04FB-Shadow bewahrt:
PHP:PHA:SEI : LDA $04FB : EOR #$02 : STA $04FB : STA $0314 : PLA:PLP:RTS
$0314-Werte: Bit 1 (ROMDIS, $02) = 0 → RAM-Overlay $C000-$DFFF,
= 1 → BASIC-ROM; Bit 7 (EPROM, $80) = 1 → RAM-Overlay $E000-$FFFF. Da
$0314 nur schreibbar ist, über den $04FB-Shadow oder $0477 gehen.
Eine Datei sektorweise an einem Offset lesen (wahlfreier Zugriff) — validiert
Um N Bytes an einem Offset zu lesen, ohne die ganze Datei zu laden. Overlay ON ($0477)
erforderlich.
BUFNOMgefüllt +JSR $DB2D(SEARCH) →X = POSNMX, Katalogsektor in BUF3.LDA $C30C,X : LDY $C30D,X : JSR $DA5D→ Deskriptor in BUF1 ($C100) geladen.- BUF1-Layout:
$C100/01Nächst-Deskriptor-Link ·$C102=FF·$C103Typ ·$C104-05load ·$C106-07end ·$C108-09exec ·$C10A-0BSektorzahl · Karte ab$C10C. sect_index = off/256,byte_in_sect = off & 255. DRIVE$C000, TRACK$C001, SECTOR$C002, RWBUF$C003/$C004setzen.JSR $DA73(XPRSEC).NBytes abPuffer + byte_in_sectkopieren.
XRWTS/XPRSEC-Schnittstelle (Handbuch, byte-exakt): DRIVE $C000, TRACK $C001 (b7=Seite
B), SECTOR $C002, RWBUF $C003/$C004. $C009 = DRVDEF, $C00A = DRVSYS.
Reproduziert aus docs/SEDORIC.md (maßgebliche, aktuelle Version auf GitHub, mit den vollständigen Rezepten).