Documentación › SEDORIC
Formato de disco SEDORIC y herramientas
Referencia primaria: el manual SEDORIC 3.0 (sedna3_0.pdf), contrastado
con «SEDORIC 3.0 à NU» de A. Chéramy y las herramientas del proyecto SCUMM-Oric / scoop-oric. Nada está
inventado: los offsets siguientes son los del manual, verificados byte a byte contra el volcado de descriptor
que el propio manual da como ejemplo.
1. Contenedor MFM_DISK
Cabecera de 256 b: "MFM_DISK" + sides (u32 LE) + tracks (u32 LE) + geometry
(u32 LE). Luego un bloque de pista de 6400 b por (cara, pista), en orden
SIDE-MAJOR: todas las pistas de la cara 0, luego todas las de la cara 1
(bloque = side * tracks + track).
Cada bloque de pista: gap inicial 60×$4E, luego por sector
12×$00 | A1 A1 A1 FE [trk side sec size] CRC | 22×$4E | 12×$00 | A1 A1 A1 FB [256 data] CRC | 38×$4E,
relleno $4E hasta 6400 b. CRC-16/CCITT (poly $1021, init $FFFF) sobre los 4
bytes de marca + los datos.
Una imagen RAW (sectores de 256 b concatenados, mismo orden side-major, sin encuadre) es aceptada
por sedoric-info y producida por oric1-emu --disk-create /
tools/sedoric_inject.py. tools/dsk_raw2mfm.py convierte RAW → MFM_DISK.
2. Sectores del sistema (pista 20)
| Sector | Papel | Campos clave |
|---|---|---|
| s1 Sistema | nombre de disco + autoexec | +9..+29 nombre de disco (21 b) · +0x1E..+0x59 INIST (60 b: comandos ASCII de arranque, separados por :, terminados por #00) |
| s2 VTOC/bitmap | contadores | +2,+3 sectores libres (LE) · +4,+5 nº de archivos (LE) |
| s4 Directorio | catálogo | +0,+1 enlace al siguiente sector dir (0=fin) · +2 high-water mark · entradas de 16 b desde +16 |
Entrada de directorio (16 b): name[9] ext[3] track sector
nsec status (V4 archivo válido = $40; bit 7 = borrado).
Nota (observada en discos Master): el contador free/files de la VTOC puede ser
una plantilla de 80 pistas superpuesta a una imagen física más pequeña — es una plantilla, no un
estado recalculado. sedoric-info informa por tanto tanto del contador VTOC como del número de archivos
realmente recorridos en el catálogo.
3. Sector descriptor de archivo
Apuntado por la entrada de directorio (track,sector). Volcado real del
manual (descriptor del archivo de sistema BANQUE nº7, p.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 | Campo | Ejemplo |
|---|---|---|
+0,+1 | enlace al siguiente descriptor (00 00 = ninguno) | 00 00 |
+2 | marcador de primer descriptor | FF |
+3 | tipo: b0=AUTO, b6=bloque de datos, b7=BASIC → $40=ML, $41=AUTO ML | 40 |
+4,+5 | dirección de carga (LE) | 00 C4 = $C400 |
+6,+7 | dirección de fin (LE) | FF C7 = $C7FF |
+8,+9 | dirección de ejecución si AUTO (LE) | 00 00 |
+0xA,+0xB | número de sectores de datos (LE) | 04 00 = 4 |
+0xC.. | mapa de sectores de datos (track,sector)×n, terminado 00 00 | 05 0B 05 0C 05 0D 05 0E 00 00 |
Este volcado corrige la antigua implementación de tap2sedoric que dejaba
+3=0 (sin tipo) y escribía el número de sectores en +9,+10 en big-endian
(solapando la dirección de ejecución). Corregido desde v1.64.0.
Descriptores encadenados (archivos > 122 sectores) — validado
Un sector descriptor solo contiene parte del mapa: el 1.er descriptor lleva la cabecera (12 b) y
luego el mapa desde +0x0C (122 pares máx., 0x0C..0xFE); cada
descriptor siguiente lleva solo el enlace +0,+1 y luego el mapa desde +0x02
(127 pares máx.). El enlace +0,+1 apunta al siguiente descriptor (00 00 =
último). +0xA,+0xB (1.er descriptor) = número total de sectores de datos.
Validado in situ: archivo de 150 sectores (2 descriptores) cargado íntegramente por LOAD.
tap2sedoric y sedoric_inject.py encadenan desde v1.65.0.
4. Herramientas
| Herramienta | Papel |
|---|---|
tap2sedoric <in.tap> -o out.dsk -b base.dsk [-n NAME.EXT] [-a] [-e EXEC] [-i "INIST"] | inyecta un .tap CSAVE en un disco MFM Sedoric (archivo + descriptor conforme + entrada dir + VTOC; -a/-e AUTO, -i autoexec de arranque) |
sedoric-info <disk.dsk> [--check FREE:FILES] | inspecciona VTOC, nombre de disco, INIST, catálogo y descriptores decodificados; --check = guarda de regresión sobre los contadores |
tools/sedoric_inject.py … | inyección en RAW (offsets directos) |
tools/dsk_raw2mfm.py <raw> <out.dsk> … | RAW → MFM_DISK (bloques side-major) |
Cadena RAW típica: oric1-emu --disk-create base.raw (luego INIT al arrancar para una VTOC real) →
sedoric_inject.py → dsk_raw2mfm.py → oric1-emu --disk-rom microdis.rom -d.
5. Inyección multiarchivo (límite superado)
Históricamente, tap2sedoric y sedoric_inject.py siempre asignaban desde
la pista 21 sector 1 sin consultar los sectores ya ocupados: una segunda inyección en el mismo disco
sobrescribía la primera.
Desde v1.64.0, ambas herramientas recorren el catálogo (cadena completa) y los mapas de sectores de los
descriptores existentes — incluidos los propios sectores de catálogo encadenados — para
marcar los sectores ocupados antes de asignar. Verificado por make test-sedoric-tools.
Encadenamiento de sectores de directorio (implementado)
Cuando el sector de catálogo actual está lleno (15 entradas), las herramientas recorren la cadena
por el enlace +0,+1; si toda la cadena está llena, asignan un sector libre, lo inicializan como
catálogo vacío y lo encadenan. Como los sectores de catálogo se localizan por enlace pista/sector, un
catálogo encadenado puede residir en cualquier sector libre. Validado in situ.
6. Ejecutar un archivo de código máquina bajo Sedoric (receta validada in situ)
Carga/ejecución verificadas en el emulador (arranque bare + LOAD). Trampas encontradas y resueltas:
| Comando / caso | Resultado |
|---|---|
teclear PROBE (nombre desnudo) en Ready | ?SYNTAX ERROR — el nombre desnudo solo lanza un BASIC AUTO |
LOADM"PROBE" | ?TYPE MISMATCH — LOADM es el comando de la ROM de casete |
CLOAD"PROBE" | sin error pero no carga nada (archivos BASIC) |
LOAD"PROBE" sobre .BIN | ?FILE NOT FOUND — .COM es la extensión por defecto |
LOAD"PROBE",J sobre AUTO | BREAK ON BYTE #5000 — ,J entra en conflicto con el flag AUTO |
LOAD"PROBE" sobre .COM AUTO (tipo $41) | carga Y ejecuta ✅ |
Receta: inyectar como .COM AUTO (tap2sedoric … -n NAME.COM -a -e EXEC),
luego en Ready: LOAD"NAME". El comando Sedoric es LOAD
(autodetecta BASIC vs binario por el byte de tipo +3), con opciones ,A (dirección) y
,J (salto).
Máster Sedoric «desnudo» arrancable (determinista)
Para validar un .COM propio hace falta un disco que arranque en Ready sin aplicación
concurrente. Método robusto, sin timing:
tools/sedoric_mkbare.py disks/SEDO40u.DSK bare.dsk # neutraliza el INIST
tools/sedoric_mkbare.py disks/SEDO40u.DSK auto.dsk 'LOAD"PROBE"' # o autolanza
Neutraliza (o reemplaza) el INIST (pista 20 sector 1, +0x1E..+0x59, CRC del sector MFM
rehecho; RAW también gestionado) → el disco cae a SEDORIC V4.0 / Ready desnudo pero sigue siendo
arrancable.
Cargar un archivo desde código máquina (receta validada in situ)
Desde un programa ML en ejecución (lanzado por LOAD), el overlay RAM de Sedoric no está
mapeado: llamar directamente a las rutinas del DOS ($DB2D búsqueda, $E0EA lectura)
cuelga. La vía robusta pasa por el vector «!» $0467 (en RAM baja, siempre
mapeado), que conmuta al overlay, ejecuta el intérprete SEDORIC ($D3AE) sobre la línea apuntada por
TXTPTR ($00E9/$00EA), y luego reconmuta y hace RTS.
LDA #<CMD : STA $E9 ; TXTPTR = direccion de la linea de comando
LDA #>CMD : STA $EA
JSR $0467 ; vector "!" : ejecuta el comando (overlay gestionado)
; ... archivo cargado; continuacion normal ...
RTS
CMD: .byte "LOAD\"SCDATA\"", 0 ; linea SEDORIC terminada por $00
Trampa: la línea debe terminar por $00, nunca por
CR ($0D). Con CR el intérprete $D3AE no completa y no hace RTS. TXTPTR
apunta al primer carácter (la L).
Conmutación overlay RAM Sedoric ↔ ROM BASIC (validado)
Desde un ML lanzado por LOAD, la ROM BASIC está mapeada en $C000-$FFFF: las variables del
sistema y las rutinas están en el overlay → conmutar antes de cualquier acceso
$C000+. Lo más sencillo: JSR $0477 (stub Sedoric en RAM baja) — un
toggle ROM↔overlay que preserva unidad/cara/IRQ mediante el shadow $04FB:
PHP:PHA:SEI : LDA $04FB : EOR #$02 : STA $04FB : STA $0314 : PLA:PLP:RTS
Valores $0314: bit 1 (ROMDIS, $02) = 0 → overlay RAM $C000-$DFFF,
= 1 → ROM BASIC; bit 7 (EPROM, $80) = 1 → overlay RAM $E000-$FFFF. Como
$0314 es de solo escritura, pasar por el shadow $04FB o $0477.
Leer un archivo por sector en un offset (acceso aleatorio) — validado
Para leer N bytes en un offset sin cargar todo el archivo. Overlay ON ($0477) obligatorio.
BUFNOMrellenado +JSR $DB2D(SEARCH) →X = POSNMX, sector de catálogo en BUF3.LDA $C30C,X : LDY $C30D,X : JSR $DA5D→ descriptor cargado en BUF1 ($C100).- Formato BUF1:
$C100/01enlace al siguiente descr. ·$C102=FF·$C103tipo ·$C104-05load ·$C106-07end ·$C108-09exec ·$C10A-0Bnº sectores · mapa desde$C10C. sect_index = off/256,byte_in_sect = off & 255. Fijar DRIVE$C000, PISTA$C001, SECTOR$C002, RWBUF$C003/$C004.JSR $DA73(XPRSEC). CopiarNbytes desdebuffer + byte_in_sect.
Interfaz XRWTS/XPRSEC (manual, byte a byte): DRIVE $C000, PISTA $C001 (b7=cara
B), SECTOR $C002, RWBUF $C003/$C004. $C009 = DRVDEF, $C00A = DRVSYS.
Reproducido de docs/SEDORIC.md (versión de referencia actualizada en GitHub, con las recetas completas).