Tachibana

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)

SectorPapelCampos clave
s1 Sistemanombre 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/bitmapcontadores+2,+3 sectores libres (LE) · +4,+5 nº de archivos (LE)
s4 Directoriocatá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
OffsetCampoEjemplo
+0,+1enlace al siguiente descriptor (00 00 = ninguno)00 00
+2marcador de primer descriptorFF
+3tipo: b0=AUTO, b6=bloque de datos, b7=BASIC → $40=ML, $41=AUTO ML40
+4,+5dirección de carga (LE)00 C4 = $C400
+6,+7dirección de fin (LE)FF C7 = $C7FF
+8,+9dirección de ejecución si AUTO (LE)00 00
+0xA,+0xBnúmero de sectores de datos (LE)04 00 = 4
+0xC..mapa de sectores de datos (track,sector)×n, terminado 00 0005 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

HerramientaPapel
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.pydsk_raw2mfm.pyoric1-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 / casoResultado
teclear PROBE (nombre desnudo) en Ready?SYNTAX ERROR — el nombre desnudo solo lanza un BASIC AUTO
LOADM"PROBE"?TYPE MISMATCHLOADM 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 AUTOBREAK 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.

  1. BUFNOM rellenado + JSR $DB2D (SEARCH) → X = POSNMX, sector de catálogo en BUF3.
  2. LDA $C30C,X : LDY $C30D,X : JSR $DA5Ddescriptor cargado en BUF1 ($C100).
  3. Formato BUF1: $C100/01 enlace al siguiente descr. · $C102=FF · $C103 tipo · $C104-05 load · $C106-07 end · $C108-09 exec · $C10A-0B nº sectores · mapa desde $C10C.
  4. sect_index = off/256, byte_in_sect = off & 255. Fijar DRIVE $C000, PISTA $C001, SECTOR $C002, RWBUF $C003/$C004.
  5. JSR $DA73 (XPRSEC). Copiar N bytes desde buffer + 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).

← Documentación · LOCI →