Sistema de archivos ROM (RFS) — Guia del desarrollador
Guia del desarrollador RFS
Esta guia es un recorrido detallado del codigo fuente RFS y el entorno de desarrollo. Explica conceptos del lenguaje ensamblador Z80 para desarrolladores que pueden no estar familiarizados con el lenguaje, recorre cada modulo fuente, documenta la arquitectura de conmutacion de bancos y muestra como agregar nuevos comandos, modificar modulos existentes y portar RFS a nuevo hardware.
Para detalles de la arquitectura de hardware y el sistema de compilacion, vease la Guia tecnica. Para la operacion orientada al usuario, vease el Manual del usuario.
Introduccion al ensamblador Z80 para programadores no familiarizados con el ensamblador
Todo el firmware RFS esta escrito en lenguaje ensamblador Z80 — el lenguaje de instrucciones nativo del procesador Zilog Z80 usado en la serie Sharp MZ. A diferencia de los lenguajes de alto nivel, el ensamblador se mapea casi directamente al hardware fisico: cada instruccion se traduce en uno o unos pocos bytes que la CPU ejecuta directamente.
Registros
El Z80 no tiene "variables" — en su lugar tiene un pequeno conjunto de registros (ubicaciones de almacenamiento rapido dentro de la CPU). Los mas usados habitualmente en RFS:
| Registro | Tamano | Rol |
|---|---|---|
| A | 8 bits | Acumulador — el registro principal para operaciones aritmeticas, logicas y de E/S. Casi cada instruccion involucra a A. |
| B, C | 8 bits | Uso general. BC juntos forman un par de 16 bits, comunmente usado como contador de bucle o conteo de bytes. |
| D, E | 8 bits | Uso general. DE juntos es un par de 16 bits, comunmente usado como puntero de origen o destino. |
| H, L | 8 bits | Uso general. HL juntos es el puntero de memoria principal de 16 bits — la mayoria de las instrucciones de lectura/escritura de memoria usan HL. |
| IX, IY | 16 bits | Registros indice — usados para direccionamiento de memoria base+offset. Mas lentos que HL pero comodos para datos estructurados. |
| SP | 16 bits | Puntero de pila — apunta a la cima de la pila de llamadas. PUSH y POP usan SP automaticamente. |
| PC | 16 bits | Contador de programa — la direccion de la instruccion actual. Se incrementa automaticamente; modificado por saltos y llamadas. |
| F | 8 bits | Registro de banderas — bits individuales establecidos por operaciones aritmeticas: Z (cero), C (acarreo), S (signo), P/V (paridad/desbordamiento). |
LD dest, src— Cargar (copiar) datos.LD A, Bcopia B en A.LD A, (HL)lee el byte en la direccion de memoria contenida en HL hacia A.LD (0x1200), Aescribe A en la direccion de memoria 0x1200.CALL addr— Llamar a una subrutina. Coloca la direccion de retorno (la instruccion siguiente) en la pila y salta aaddr. Equivalente a una llamada de funcion.RET— Retornar de una subrutina. Saca la direccion de retorno de la pila y salta a ella.JP addr— Salto incondicional aaddr.JP Z, addrsalta solo si la bandera Cero esta activada (es decir, la ultima operacion produjo cero).JR offset— Salto relativo corto (-128 a +127 bytes). Mas rapido y compacto que JP para ramas cercanas.DJNZ offset— Decrementa B y salta si no es cero (Not Zero). La instruccion canonica de bucle del Z80:LD B, 10 / LOOP: ... / DJNZ LOOPrepite 10 veces.ADD A, n— Suma n a A.SUB nresta.AND n,OR n,XOR n— logica de bits sobre A.IN A, (port)— Lee de un puerto de E/S hacia A.OUT (port), A— escribe A en un puerto de E/S. Asi es como el Z80 se comunica con el hardware (el WD1773, el controlador SPI, el latch de bancos, etc.).PUSH rr / POP rr— Guardar/restaurar un par de registros de 16 bits hacia/desde la pila.EI / DI— Habilitar / Deshabilitar interrupciones. El codigo que no debe ser interrumpido (p. ej. operaciones de cinta criticas en el tiempo) se envuelve entre DI y EI.
El Z80 ofrece varias maneras de especificar de donde proceden o hacia donde van los datos:
Sintaxis del ensamblador GLASS
- Inmediato:
LD A, 42— el valor esta incrustado en los propios bytes de la instruccion. - Registro:
LD A, B— los datos proceden de o van a un registro. - Indirecto (via HL):
LD A, (HL)— HL contiene una direccion de memoria; los datos se leen de esa direccion. - Extendido (direccion directa):
LD A, (0x1200)— la direccion es una constante literal de 16 bits en la instruccion. - Indexado:
LD A, (IX+5)— IX contiene una direccion base; se suma 5 para obtener la direccion efectiva. Usado en RFS para acceder a campos dentro de estructuras de datos de formato fijo.
RFS usa el ensamblador GLASS Z80. Caracteristicas clave de la sintaxis:
- Los comentarios comienzan con
;— todo lo que esta a la derecha de un punto y coma se ignora. - Las etiquetas son identificadores seguidos de
:. Una etiqueta al inicio de una linea nombra la direccion de la instruccion siguiente. EQUdefine una constante:BELL EQU 007H— el ensamblador reemplaza cada aparicion de BELL con 0x07.DB(Define Byte) inserta bytes crudos:DB 0x41, 0x42emite dos bytes. Usado para cadenas y tablas de busqueda.DW(Define Word) inserta valores little-endian de 16 bits:DW HANDLERemite la direccion de la etiqueta HANDLER.ORG addrestablece el origen de ensamblaje — el codigo subsiguiente se ensambla como si residiera enaddr.INCLUDE "file.asm"incluye textualmente otro archivo en la posicion actual.IF / ENDIFensamblaje condicional:IF BUILD_SFD700 = 1 ... ENDIF— las instrucciones encerradas solo se ensamblan cuando la condicion es verdadera. Asi es como RFS construye cuatro variantes de firmware diferentes a partir de un solo arbol de fuentes.
Arbol de fuentes
| Ruta | Contenido |
|---|---|
asm/ |
Todos los archivos fuente de ensamblador Z80 |
asm/include/ |
Definiciones compartidas y archivos de configuracion |
asm/dis/ |
Archivos de referencia desensamblados para SA-5510 y XPATCH |
tools/ |
Scripts de compilacion, ensamblador GLASS, binarios de utilidades |
MZF/ |
Archivos de aplicacion en formato MZF, organizados por tipo de maquina |
MZB/ |
Aplicaciones binarias rellenadas por sectores (generadas por la compilacion) |
roms/ |
Salida de compilacion — imagenes ROM e imagenes de tarjeta SD |
releases/ |
Binarios de version preconstruidos |
config/ |
Definiciones de formato de disco CP/M (diskdefs) |
cpmtools/ |
Codigo fuente de cpmtools (submodulo) |
src/ |
Codigo fuente de las herramientas de soporte |
Configuracion: rfs_definitions.asm
Este es el archivo de configuracion central, incluido por cada uno de los demas archivos fuente mediante
Indicadores de objetivo de compilacion
INCLUDE "rfs_definitions.asm". Cada opcion en tiempo de ensamblaje se controla aqui. Las secciones clave:
HW_SPI_ENA EQU 1 ; 1 = hardware SPI on RomDisk v2+ PCB SW_SPI_ENA EQU 0 ; 1 = software bit-bang SPI (RomDisk v1) PP_SPI_ENA EQU 0 ; 1 = SPI via parallel port (RomDisk v1 alternative) FUSIONX_ENA EQU 0 ; 1 = running on tranZPUter FusionX KUMA80_ENA EQU 0 ; 1 = Kuma 40/80 upgrade present VIDEOMODULE_ENA EQU 0 ; 1 = 40/80 colour video module present BUILD_ROMDISK EQU 0 ; 1 = build for RomDisk card BUILD_SFD700 EQU 0 ; 1 = build for SFD-700 floppy interface BUILD_PICOZ80 EQU 1 ; 1 = build for picoZ80 board ENADEBUG EQU 0 ; 1 = enable debug output during assembly
Exactamente un indicador
Constantes de direccion
BUILD_* debe estar establecido en 1 a la vez. Todos los bloques de ensamblaje condicional a lo largo del codigo fuente prueban estos indicadores para incluir o excluir codigo especifico de plataforma.
UROMADDR EQU 0E800H ; Base address of the User ROM window UROMBSTBL EQU UROMADDR + 020H ; Bank-switch table entry point (fixed offset) RFSJMPTABLE EQU UROMADDR + 0B0H ; RFS jump table start FDCROMADDR EQU 0F000H ; FDC ROM address (SFD-700 MROM location) ; SFD-700 specific bank defaults (only assembled when BUILD_SFD700 = 1): BNKDEFMROM_MZ80A EQU 0 ; Default MROM bank for MZ-80A (AFI ROM) BNKDEFMROM_MZ700 EQU 1 ; Default MROM bank for MZ-700 (AFI ROM) BNKDEFUROM EQU 2 ; Default UROM bank for RFS (starts at 8KB in Flash)
Estas constantes definen donde se situa cada ventana de ROM en el espacio de direcciones del Z80. El codigo compilado para la ventana User ROM siempre se ensambla con
Definiciones de caracteres y de control
ORG 0xE800; el codigo para la ventana Monitor ROM se ensambla en ORG 0x0000.
Los caracteres de control ASCII estandar se definen como constantes con nombre para que el codigo fuente sea autodocumentado:
BELL EQU 007H ; Terminal bell CR EQU 00DH ; Carriage return LF EQU 00AH ; Line feed CS EQU 00CH ; Clear screen SPACE EQU 020H ; ASCII space DELETE EQU 07FH ; Delete key
La conmutacion de bancos en detalle
La conmutacion de bancos es el corazon de la arquitectura RFS. Entenderla es esencial antes de modificar cualquier archivo fuente.
Por que es necesaria la conmutacion de bancos
El Sharp MZ-80A da al User ROM solo 2 KB de espacio de direcciones (0xE800-0xEFFF). 2 KB pueden contener solo unos pocos cientos de instrucciones — ni de lejos suficiente para un sistema de archivos, un ensamblador, un desensamblador, un controlador de cinta, un controlador de tarjeta SD y un CBIOS de CP/M. La solucion es conmutar fisicamente cuales 2 KB de un chip Flash de 512 KB son visibles en ese rango de direcciones. Almacenando 12 bancos RFS de 2 KB distintos (bancos 0-11) en el chip Flash y conmutando entre ellos bajo demanda, RFS consigue efectivamente 24 KB de codigo ROM — con otros 4 bancos (12-15) reservados para el CBIOS de CP/M. Ademas, tres de las 16 paginas del Monitor ROM (bancos 6, 7 y 9) contienen las tablas de codigos de operacion del ensamblador/desensamblador Z80 y las cadenas de mensajes RFS, ampliando el espacio ROM disponible sin consumir capacidad del User ROM.
El stub de conmutacion de bancos
Cada banco comienza con una copia identica del stub de conmutacion de bancos que ocupa los primeros 32 bytes del banco (0xE800-0xE81F). Este stub proporciona:
Formato de la tabla de comandos (rfs.asm)
- Una puerta de llamada estandar: Cualquier banco puede llamar a cualquier rutina en cualquier otro banco llamando al stub con el numero de banco destino y la direccion destino. El stub escribe el numero de banco en el latch de hardware (tipicamente una escritura a un puerto de E/S), luego llama a la direccion solicitada. El destinatario se ejecuta en el nuevo banco y, cuando retorna, el stub vuelve a conmutar al banco original.
- Un punto de entrada consistente: Como el stub esta en un offset fijo (0xE800 + 0x20 para la tabla de conmutacion de bancos), el codigo en el banco 0 puede encontrar de forma fiable el stub en el banco 3 aunque nunca haya visto las direcciones internas del banco 3.
El despachador de comandos del monitor en
rfs.asm usa una tabla de comandos compacta. Cada entrada describe un comando y se dispone de la siguiente manera:
; One command table entry:
;
; DB FLAGS ; 1 byte: END|MATCH|BANK[5:3]|SIZE[2:0]
; DB "COMMAND" ; SIZE bytes: the command string (no null terminator)
; DW HANDLER_ADDR ; 2 bytes: address of the handler routine in the named bank
;
; Flags byte:
; Bit 7 = 1: End of table marker (last entry).
; Bit 6 = 1: Exact match required (command must be entire input, no trailing chars).
; Bits 5:3 Bank number where HANDLER_ADDR lives (0-11 for RFS, 12-15 for CBIOS).
; Bits 2:0 Length of the command string in bytes.
;
; Example - the ASM command (all builds, lives in bank 6, 3-char string):
CMDTABLE:
DB 000H | 000H | 030H | 003H ; FLAGS: not-end, not-exact, bank 6, length 3
DB "ASM" ; Command string
DW ASM_MAIN ; Handler address in bank 6
El despachador lee la linea de entrada del monitor, recorre la tabla y, para cada entrada:
- Compara la entrada con la cadena del comando (sin distincion de mayusculas/minusculas en algunas compilaciones).
- Si coincide, extrae el numero de banco y la direccion del handler de la entrada de la tabla.
- Realiza una conmutacion de banco al banco destino.
- Llama al handler con cualquier entrada restante (parametros) disponible en el bufer de entrada del monitor.
CMDTABLE2 para la compilacion SFD-700, y CMDTABLE para la compilacion RomDisk/picoZ80. Ambas estan estructuradas de forma identica pero contienen conjuntos de comandos diferentes — en particular, la tabla SFD-700 excluye los comandos de tarjeta SD (IC, LC, SC, EC, DUC, T2SD, SD2T) ya que ese hardware no tiene tarjeta SD. Los comandos ASM y DASM estan presentes en ambas tablas.
Recorridos por los modulos
rfs.asm — Despachador de comandos (User ROM banco 0)
Rol: El punto de entrada para toda la funcionalidad RFS. Cuando el monitor SA-1510 no reconoce un comando, pasa el control al punto de entrada del User ROM en 0xE800. Este siempre es el banco 0.
Secciones clave:
rfs_bank1.asm — Controlador de disco flexible (User ROM banco 1)
- Stub de conmutacion de bancos (0xE800-0xE81F): La puerta de llamada entre bancos descrita arriba. Cada banco tiene una copia identica.
- Tabla de conmutacion de bancos (0xE800 + 0xB0): Una tabla de saltos que mapea numeros de banco a sus direcciones fisicas de ROM Flash. Se modifica en el arranque si el hardware requiere direccionamiento de bancos no secuencial.
- Tabla de comandos (CMDTABLE / CMDTABLE2): La lista de todos los comandos RFS con su banco y direccion del handler.
- Bucle principal del despachador: Lee el bufer de entrada del monitor, recorre la tabla de comandos, realiza la conmutacion de banco y llama al handler. Si ningun comando coincide, retorna al monitor SA-1510 para que pueda imprimir el error "?".
- Inicializacion de RFS: En la primera entrada tras el reset, RFS detecta la plataforma de hardware (a partir del registro MODE en el SFD-700, o a partir de indicadores en RomDisk), inicializa el SPI y la tarjeta SD, y establece la unidad inicial en 0.
BUILD_SFD700 = 1, rfs.asm se ensambla con ORG 0xE000 / ALIGN 0xE300 en lugar de ORG 0xE800, porque el SFD-700 mapea su ventana User ROM en 0xE300-0xEFFF (0xE000-0xE2FF esta reservado para la E/S mapeada en memoria del MZ-700).
Rol: Implementa los comandos de disco flexible — arranque de disco flexible (F / FL), directorio de disco flexible (FD) y el salto directo a AFI (f). El conjunto completo de comandos FDC se ensambla en todas las compilaciones.
Funciones clave:
rfs_bank2.asm — Controlador de tarjeta SD (User ROM banco 2)
- FLOPPY (FL): Solicita un numero de unidad (si no se proporciona en la linea de comandos), inicializa el disco, lee el sector de arranque, verifica la firma del disco, extrae la informacion del programa (nombre, direccion de carga, tamano, direccion de ejecucion), carga el programa en memoria y lo ejecuta.
- FDDIR (FD): Lista el directorio de archivos en un disco flexible. Acepta un numero de unidad opcional (1-4, por defecto 1). Lee el sector de arranque, verifica el formato de disco MZ-700, luego escanea los sectores de directorio mostrando nombres de archivo, direcciones de carga, direcciones de ejecucion y tamanos de archivo.
- FDCK: Lee el byte en 0xF000 para verificar que el ROM AFI esta presente y es distinto de cero, luego llama directamente a 0xF000. Este es el comando f (minuscula) en todas las compilaciones.
- Al final del banco, una directiva
ALIGN 0xF000asegura que la imagen ROM del SFD-700 posiciona el ROM de arranque AFI exactamente en 0xF000 en la distribucion del Flash.
Rol: El subsistema completo de tarjeta SD — inicializacion SPI, protocolo de comandos de tarjeta SD, y las rutinas de directorio y E/S de archivos SDCFS. En la compilacion SFD-700, el codigo del controlador de tarjeta SD no se ensambla (el hardware SFD-700 no tiene interfaz de tarjeta SD); la ranura del banco esta presente en la imagen ROM pero contiene solo el stub de conmutacion de bancos.
Funciones clave:
rfs_bank3.asm — Utilidades de memoria (User ROM banco 3)
- Controlador SPI (hardware o software): El ensamblaje condicional selecciona entre SPI por hardware (usando los registros del controlador SPI del RomDisk v2) y SPI por software bit-bang (conmutando bits individuales de puertos de E/S para temporizar el bus SPI). La ruta de SPI por hardware es sustancialmente mas rapida y se usa en todas las placas actuales (
HW_SPI_ENA = 1). - Inicializacion de tarjeta SD (SDINIT): Implementa la secuencia de inicializacion de la tarjeta SD — envia CMD0 (GO_IDLE), CMD8 (SEND_IF_COND), ACMD41 (SD_SEND_OP_COND) para cambiar la tarjeta del modo SPI al estado activo. Maneja tanto tarjetas SD como SDHC/SDXC comprobando la respuesta OCR.
- Lectura de sector (SDREAD): Envia CMD17 (READ_SINGLE_BLOCK) con una direccion de sector de 32 bits, espera el token de inicio de datos (0xFE), luego lee 512 bytes en un bufer de RAM del Z80. Usa el modo rafaga de SPI por hardware donde este disponible.
- Escritura de sector (SDWRITE): Envia CMD24 (WRITE_BLOCK), el token de inicio de datos, 512 bytes de datos y el CRC. Espera a que se borren la respuesta de escritura y la senal de ocupado.
- Lectura de directorio SDCFS (SDDIR): Lee el directorio de los primeros 8 KB de la imagen de la unidad activa y construye una cache de directorio residente en RAM usada por los comandos IC, LC, SC y EC.
- Carga de archivo SDCFS (SDLOAD): Dado un numero de archivo del directorio, calcula la direccion de sector del bloque de 64 KB del archivo, lee los bytes del tamano real del archivo y los carga en la direccion del Z80 especificada en el campo LOAD ADDR de la entrada de directorio.
- Guardado de archivo SDCFS (SDSAVE): Asigna una nueva ranura de directorio (o encuentra una entrada existente con el mismo nombre para sobrescribir), establece los campos START SECTOR, SIZE, LOAD ADDR y EXEC ADDR, luego escribe los datos del archivo en el bloque de 64 KB apropiado.
Rol: Implementa los comandos D (volcado hexadecimal), M (edicion de memoria), CP (copia de memoria), IN (lectura de puerto de E/S) y OUT (escritura de puerto de E/S), que estan disponibles en todas las compilaciones. Los comandos DUC (volcado de archivo de tarjeta SD), T2SD (cinta a SD) y SD2T (SD a cinta) tambien se implementan aqui pero solo se ensamblan para las compilaciones RomDisk / picoZ80 — la compilacion SFD-700 los excluye porque no hay tarjeta SD.
Volcado hexadecimal (D): Lee hasta 20 lineas de 16 bytes cada una del rango de direcciones destino. Para cada linea imprime la direccion hexadecimal de 4 digitos, 16 valores de byte en hexadecimal (con un espacio entre cada 4 bytes) y los 16 caracteres ASCII (usando un punto para los bytes no imprimibles). El Sharp MZ usa una codificacion de caracteres inusual — el banco 5 proporciona la tabla de conversion de Sharp a ASCII usada aqui.
Editor de memoria (M): Presenta cada byte por turno, mostrando la direccion y el valor actual. El usuario puede teclear un nuevo valor hexadecimal (1 o 2 digitos) y pulsar Enter para escribirlo, o pulsar Enter solo para dejarlo sin cambios. Pulsar Ctrl+C o una secuencia de escape especifica sale.
Comandos de puerto de E/S (IN / OUT): IN lee uno o mas puertos de E/S del Z80 (direcciones de 2 o 4 digitos hexadecimales, separadas por comas) usando
rfs_bank4.asm — Controlador de CMT (User ROM banco 4)
IN A,(C) e imprime cada valor como 2 digitos hexadecimales. OUT escribe en uno o mas puertos — cada entrada es una direccion de puerto seguida de dos puntos y un valor hexadecimal de 2 digitos (p. ej. OUTD0:01,D1:80), ejecutada con OUT (C),A. Ambos comandos admiten todo el espacio de direcciones de puertos de E/S de 16 bits del Z80.
T2SD y SD2T: Estos comandos realizan una copia bidireccional transparente entre la cinta (CMT) y la tarjeta SD. T2SD llama a la rutina de carga de CMT del banco 4 para leer un archivo de cinta en RAM, luego llama a la rutina de guardado de SD del banco 2 para escribirlo en la unidad activa. SD2T llama a la rutina de carga de SD del banco 2 para poner el archivo en RAM, luego llama a la rutina de guardado de CMT del banco 4 para escribirlo en cinta. Ambas direcciones usan el directorio SDCFS para mantener nombres de archivo, tamanos y direcciones.
Rol: Implementa los comandos de cinta (CMT) L/LT, LTNX, S/ST y V.
El Sharp MZ-80A usa una interfaz de cassette Kansas City Standard a 1200 baudios. Los bytes se codifican como rafagas de tono de 1200 Hz (bit 0) o 2400 Hz (bit 1). Las rutinas de cinta son criticas en el tiempo — deben leer o escribir cada bit dentro de una ventana de temporizacion estrecha. Usan el chip temporizador 8253 (o bucles con conteo de ciclos de CPU en plataformas sin el temporizador) para medir la frecuencia del tono entrante y generar la forma de onda saliente. Las interrupciones se deshabilitan (
rfs_bank5.asm — Funciones de utilidad (User ROM banco 5)
DI) durante toda la operacion de cinta para evitar la disrupcion de la temporizacion.
El formato de cinta MZF prefija cada programa con una cabecera de 128 bytes que contiene el tipo de archivo, el nombre de archivo, la longitud de datos, la direccion de carga y la direccion de ejecucion — los mismos campos almacenados en la entrada de directorio SDCFS. Por eso la copia SD<->cinta es transparente: el formato de la cabecera es identico.
Rol: Una biblioteca de rutinas compartidas llamadas por otros bancos. Como la conmutacion de bancos es costosa (requiere la secuencia de desbloqueo en placas v2+), las rutinas usadas con frecuencia se centralizan aqui para minimizar la sobrecarga de conmutacion.
Rutinas clave:
rfs_bank6.asm — Tabla de codigos de operacion ASM/DASM 1 (User ROM banco 6)
- PRTHEX: Imprime el registro A como dos digitos hexadecimales en la pantalla.
- PRTHL: Imprime el registro HL como cuatro digitos hexadecimales.
- PRTSTR: Imprime una cadena terminada en nulo desde (HL) en la pantalla, manejando la conversion de codificacion de caracteres de Sharp.
- INPHEX: Lee un numero hexadecimal (hasta 4 digitos) del teclado, devolviendo el valor en HL.
- STRCMP: Compara dos cadenas terminadas en nulo.
- SUBSTR: Extrae una subcadena, usada por el despachador de comandos para separar los nombres de comando de los parametros.
- WAITKEY: Espera una pulsacion de tecla y devuelve el codigo de tecla en A. Usada para las pausas de "pulse cualquier tecla para continuar" en los listados de directorio IC e IR.
Rol: Almacena la primera mitad de las tablas de busqueda de codigos de operacion del Z80 usadas tanto por los comandos del ensamblador (ASM) como del desensamblador (DASM), mas la funcion PRINTMSG y la infraestructura de cadenas de mensajes. Las tablas de codigos de operacion mapean cadenas de mnemonicos Z80 a bytes de codigo de operacion y viceversa. El ensamblador y el desensamblador estan disponibles en todas las compilaciones (RomDisk, picoZ80, SFD-700 y FusionX).
La funcion PRINTMSG lee las cadenas de mensajes del banco MROM 9 a un bufer de RAM antes de imprimirlas, ya que las funciones del Monitor ROM (PRNT, ?DSP, etc.) requieren que el banco MROM del monitor este activo durante la salida de caracteres. El banco MROM 6 correspondiente tambien contiene datos de tablas de codigos de operacion en el espacio de 4 KB del Monitor ROM, proporcionando espacio adicional para el conjunto completo de instrucciones del Z80 incluyendo todas las variantes con byte de prefijo (CB, DD, ED, FD).
rfs_bank7.asm — Tabla de codigos de operacion ASM/DASM 2, DASM, pruebas (User ROM banco 7)
Rol: Almacena la segunda mitad de las tablas de busqueda de codigos de operacion del Z80, la rutina principal del desensamblador DASM, la prueba de DRAM R y la prueba de temporizador T.
Desensamblador (DASM): Lee bytes de codigo maquina de la direccion destino, decodifica cada instruccion (usando las tablas de codigos de operacion de los bancos 6 y 7), e imprime la direccion, los bytes hexadecimales y el mnemonico de cada instruccion. Maneja todos los bytes de prefijo del Z80 (CB, DD, ED, FD) y las instrucciones extendidas.
Prueba de DRAM (R): Realiza una escritura/verificacion de patron de bit progresivo en todo el espacio de RAM de usuario (0x1200-0xCFFF). Reporta cualquier direccion que falle. Util para diagnosticar chips de RAM defectuosos — un modo de fallo comun en maquinas antiguas.
rfs_bank8.asm — Ensamblador Z80 (User ROM banco 8)
Rol: Implementa el comando del ensamblador interactivo ASM.
Ensamblador interactivo (ASM): Presenta un prompt de entrada de linea en la direccion destino. El usuario teclea mnemonicos Z80 (p. ej.
rfs_bank9.asm — Funciones de directorio y archivos de ROM (User ROM banco 9)
LD A, 42) que se analizan, se ensamblan a bytes de codigo maquina y se escriben directamente en la direccion destino en RAM. La direccion avanza por el tamano de cada instruccion ensamblada. Esto permite ensamblar pequenas rutinas directamente en el hardware sin un PC externo. Las tablas de busqueda de codigos de operacion en los bancos 6 y 7 (y los bancos MROM 6 y 7) se usan para la traduccion de mnemonico a codigo de operacion.
Rol: Contiene las funciones de enumeracion de directorio de ROM, busqueda de archivos, carga de archivos e impresion que se movieron del banco 0 (el banco del despachador de comandos) para liberar espacio en el banco 0 para entradas adicionales de la tabla de comandos e infraestructura. Las funciones clave incluyen DIRROM9 (listado de directorio de ROM), FINDSDX9 (busqueda de archivos), ISMZF9 (validacion de cabecera MZF) y _PRTMZF9 (visualizacion de entrada MZF).
rfs_bank11.asm — Pantalla de ayuda (User ROM banco 11)
Rol: Almacena el texto paginado de la pantalla de ayuda (movido del banco 6 para dejar espacio para las tablas de codigos de operacion). La pantalla de ayuda se almacena como una secuencia de cadenas terminadas en nulo (una por linea). El comando H las imprime con paginacion automatica, llamando a la rutina WAITKEY del banco 5 en cada limite de pantalla completa.
rfs_mrom.asm — Utilidades del Monitor ROM (Monitor ROM banco 3)
Rol: Proporciona las rutinas de escaneo de ROM y carga de archivos MZF que deben ejecutarse desde el espacio del Monitor ROM en lugar del espacio del User ROM.
Por que un banco de Monitor ROM separado? Los comandos IR y LR necesitan enumerar los archivos MZF almacenados en los chips Flash del User ROM (los bancos del User ROM por encima del 15 contienen programas MZF empaquetados). Para escanear un banco del User ROM, la CPLD debe conmutar la ventana User ROM para que apunte a ese banco. Pero el propio codigo de escaneo reside en el User ROM — si conmuta el banco del User ROM, se reemplaza a si mismo instantaneamente con un banco diferente y se cuelga.
La solucion es colocar el bucle de escaneo en el banco 3 del Monitor ROM. La conmutacion de bancos del Monitor ROM es independiente de la conmutacion de bancos del User ROM. La rutina de escaneo de MROM puede conmutar libremente los bancos del User ROM (para enumerar la lista de cabeceras MZF de cada banco) sin perturbar su propio contexto de ejecucion.
Funciones clave:
Modulos CBIOS de CP/M
- ROMDIR: Escanea todos los bancos del User ROM por encima del 15, lee cada cabecera MZF y construye un directorio de ROM residente en RAM usado por el comando IR.
- ROMLOAD: Dado un numero de archivo del directorio de ROM, lee los datos MZF del banco del User ROM apropiado en el LOAD ADDR especificado en la cabecera, luego salta opcionalmente a EXEC ADDR.
Los cuatro bancos User ROM del CBIOS (12-15) y el banco Monitor ROM del CBIOS (2) implementan juntos el CBIOS completo de CP/M 2.2. Cada banco proporciona un subsistema:
cbios.asm (Monitor ROM banco 2): La tabla de puntos de entrada del CBIOS — los 17 vectores de la API de CP/M (de BOOT a SECTRN) son direcciones de salto dentro de este modulo. Tambien contiene las tablas de parametros de disco (estructuras DPH, DPB que indican a CP/M la geometria de cada unidad de disco), las secuencias de arranque en frio/en caliente y el controlador de disco ROM (lee sectores del Flash del User ROM).
cbios_bank1.asm (User ROM banco 12): Salida de audio (tono de campana y melodia usando el PPI 8255 y el zumbador del MZ-80A), rutinas de reloj en tiempo real usando el temporizador 8253, y entrada de teclado con auto-repeticion (tecla mantenida > 500 ms se repite a ~10 Hz, igualando el comportamiento que los usuarios esperan de un teclado moderno).
cbios_bank2.asm (User ROM banco 13): Controlador de pantalla — salida de caracteres en la posicion actual del cursor, desplazamiento, borrado de pantalla, posicionamiento del cursor. Tambien el emulador de terminal ANSI: una maquina de estados que reconoce secuencias de escape VT52/VT100 (codigos CSI) y las traduce en las operaciones de pantalla equivalentes del MZ-80A. Esto hace que las aplicaciones de CP/M que asumen un terminal inteligente (WordStar, Turbo Pascal, etc.) funcionen correctamente sin ninguna modificacion de esas aplicaciones.
cbios_bank3.asm (User ROM banco 14): Controlador de disco de tarjeta SD para CP/M. Traduce las solicitudes de lectura/escritura de sectores de 128 bytes de CP/M en operaciones SDCFS sobre las imagenes de disco de CP/M almacenadas despues del limite de 256 MB en la tarjeta SD. Incluye la tabla de sesgo de sectores usada por SECTRN para mejorar el rendimiento del acceso a disco.
cbios_bank4.asm (User ROM banco 15): Controlador de disco flexible para CP/M. Usa el WD1773 (mediante SFD-700) o un controlador de disco flexible equivalente para atender las solicitudes de lectura/escritura de disco de CP/M en unidades de disco flexible fisicas. Los datos se leen sin invertir (a diferencia del ROM AFI del MZ-80A, que usa datos invertidos) porque el CBIOS escribe su propio formato reinvertido. Cuando se controla a traves de la tarjeta MZ80AFI, consulta el informe de tamano de sector del controlador (puerto 0xDF) para distinguir los discos de 256 bytes del MZ-80A de los discos de 128 bytes del MZ-80K, y puede arrancar/leer directamente discos CP/M originales (sin convertir) del MZ-80K — identificados por el marcador de arranque no invertido
01h + IPLPRO — asignandolos a las unidades CP/M C:/D: (los ayudantes ?SETDRVMAP / ?SELDRIVE asignan las unidades de disco flexible fisicas a las letras de unidad CP/M apropiadas en el arranque en frio).
Agregar un nuevo comando del monitor
Para agregar un nuevo comando FOO que reside en el banco User ROM 3 (utilidades de memoria):
- Escribir el handler en rfs_bank3.asm: Anadir una rutina etiquetada
FOO_CMD:que implemente el comando. Los parametros estan disponibles en el bufer de entrada del monitor (HL apunta al primer caracter despues del nombre del comando). Retornar conRETcuando termine. - Agregar una entrada a la tabla de comandos en rfs.asm: En la
CMDTABLEapropiada (oCMDTABLE2para SFD-700), anadir:
; FLAGS: not-end (bit7=0), not-exact (bit6=0), bank 3 (bits5:3 = 011 = 0x18), length 3 (bits2:0 = 011)
DB 000H | 000H | 018H | 003H
DB "FOO"
DW FOO_CMD
- Actualizar el texto de ayuda en rfs_bank6.asm: Anadir una linea que describa el nuevo comando a las cadenas de texto de la pantalla de ayuda.
- Recompilar: Ejecutar
./build.sh. El ensamblador reportara cualquier desbordamiento de tamano si el banco 3 es ahora mayor de 2 KB — en ese caso, eliminar o comprimir otro codigo en ese banco.
Agregar una nueva plataforma de hardware
Para portar RFS a un nuevo objetivo de hardware:
- Agregar un indicador de compilacion en
rfs_definitions.asm:BUILD_NEWBOARD EQU 0(establecer en 1 al compilar para el nuevo objetivo). - Agregar constantes de direccion si el nuevo hardware mapea las ventanas de ROM en direcciones diferentes.
- Agregar bloques de ensamblaje condicional a lo largo del codigo fuente donde el comportamiento especifico del hardware difiera — direcciones de puertos de E/S para el latch de bancos, distribucion de registros del controlador SPI, deteccion de presencia de tarjeta SD, etc. Seguir el patron de los bloques existentes
IF BUILD_ROMDISK = 1 ... ENDIF. - Agregar un nuevo script de compilacion (o extender
make_roms.sh) para empaquetar la imagen ROM para la distribucion del chip Flash del nuevo objetivo. - Actualizar la comprobacion de prerrequisitos en
build.shsi el nuevo objetivo necesita herramientas adicionales.
Consejos de depuracion
Habilitar salida de depuracion: Establecer
ENADEBUG EQU 1 en rfs_definitions.asm antes de compilar. Esto incluye salida diagnostica adicional en puntos estrategicos de la inicializacion de la tarjeta SD y las rutinas SDCFS.
Usar el desensamblador integrado: En las compilaciones SFD-700, teclear DASM addr para desensamblar el codigo ensamblado en RAM. Esto es invaluable para verificar que una rutina recien ensamblada fue codificada correctamente por el comando ASM.
Usar el volcado hexadecimal: D E800 muestra los primeros 320 bytes del banco User ROM actual — util para verificar que el latch de bancos esta seleccionando el banco esperado.
Prueba de DRAM tras cualquier modificacion de RAM: Teclear R para ejecutar una prueba de DRAM exhaustiva siempre que se anadan nuevas estructuras de datos residentes en RAM. Esto detecta errores de direccionamiento temprano antes de que aparezcan como cuelgues misteriosos.
Guarda de conmutacion de bancos: En las placas RomDisk v2+, nunca colocar un DJNZ ni ninguna otra instruccion de bucle que abarque 0xEFF8-0xEFFF. El latch codificado interpreta las lecturas de ese rango como la secuencia de desbloqueo y puede conmutar bancos de forma inesperada.
Entorno de compilacion
La cadena de herramientas de compilacion de RFS es sencilla — solo se requieren un entorno de ejecucion de Java y el ensamblador GLASS Z80 para los componentes de ensamblador Z80. La forma recomendada de compilar es el script de configuracion automatizado para tu plataforma (consulta Configuracion y compilacion automatizadas mas abajo); los pasos de compilacion manual y de FusionX que siguen son para usuarios avanzados y recompilaciones parciales. El script de compilacion global de FusionX
Prerrequisitos
build.sh automatiza todo el proceso.
# Install Java runtime (required for the GLASS assembler) sudo apt install -y default-jre git # Clone the repository git clone https://git.eaw.app/eaw/tzpuFusionX.git cd tzpuFusionX # Initialise git submodules git submodule update --init --recursive
El archivo JAR del ensamblador GLASS Z80 viene incluido en el repositorio en
Configuracion y compilacion automatizadas (recomendado)
software/tools/glass-0.5.1.jar — no es necesaria ninguna descarga aparte. Cualquier entorno de ejecucion de Java 8 o posterior funcionara.
La forma recomendada de compilar RFS es el script de configuracion autonomo para tu plataforma. Instala los prerrequisitos (un JRE de Java para el ensamblador GLASS Z80, una cadena de herramientas de C +
make para compilar el submodulo incluido cpmtools, ademas de perl/git/coreutils; en Windows, Git Bash + Java), clona el repositorio, descarga el paquete de contenido de ~110 MB (RFS_Files.zip), escribe el archivo de entorno y puede ejecutar la primera compilacion — todo de forma interactiva, con valores predeterminados sensatos que puedes aceptar pulsando Enter. Copia solo el archivo unico para tu plataforma y ejecutalo.
macOS / Linux / WSL — setup_RFS.sh
chmod +x setup_RFS.sh
./setup_RFS.sh
Windows 10 / 11 — setup_RFS_windows_native.ps1 (recomendado — nativo, sin WSL). Desde un simbolo del sistema de PowerShell:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\setup_RFS_windows_native.ps1
El script nativo usa winget para instalar Git for Windows (que proporciona bash, coreutils, perl y curl) y un JRE Temurin 17 (Java), clona el repositorio, descarga el paquete de contenido y ejecuta
./build.sh a traves de Git Bash — sin WSL, Docker ni reinicio. No se requiere ningun compilador de C porque se incluyen dos herramientas host precompiladas (tools\cpmcp.exe y tools\sdtool.exe).
Windows 10 / 11 — setup_RFS_windows.ps1 (alternativa — compila dentro de WSL2 / Ubuntu). Desde una PowerShell de Administrador:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\setup_RFS_windows.ps1
Esta variante de WSL instala WSL2 + Ubuntu si aun no estan presentes (se necesita un reinicio unico — reinicia, inicia Ubuntu una vez para crear tu usuario de Linux, y despues vuelve a ejecutar el script), y despues ejecuta
setup_RFS.sh dentro de Ubuntu.
Establece la variable de entorno
RFS_REPO_URL para anular la URL del repositorio predeterminada (https://git.eaw.app/eaw/RFS.git) sin editar el script, y RFS_FILES_URL para apuntar a un paquete de contenido alternativo.
Salida y recompilacion. Las imagenes ROM y las imagenes de tarjeta SD se escriben en
Compilacion
roms/. Para recompilar mas tarde, entra en el checkout; en macOS ejecuta primero source ./rfs_env.sh para poner GNU coreutils y el JRE en el PATH; despues ejecuta ./build.sh -m para la primera compilacion (procesa las fuentes MZF en MZB/) y ./build.sh para las compilaciones posteriores. En Windows (nativo), ejecuta los mismos comandos ./build.sh desde Git Bash dentro del checkout.
# Build all Z80 assembly ROMs and MZF files (includes RFS) ./build.sh --asm # Build output appears in software/roms/ ls software/roms/*.rom software/roms/*.mzf
El script de compilacion ensambla cada objetivo ROM y MZF usando el ensamblador GLASS, pasando las rutas de inclusion y los indicadores de compilacion apropiados. Las variantes de MS BASIC (MZ-80A, MZ-700, TZ40, TZ80) se construyen a partir del mismo archivo fuente con distintos indicadores
BUILD_VERSION establecidos mediante archivos de inclusion generados.
Salida de compilacion:
| Salida | Descripcion |
|---|---|
monitor_sa1510.rom |
ROM del monitor SA-1510 |
monitor_80c_sa1510.rom |
Monitor SA-1510 con soporte de 80 columnas |
monitor_1z-013a.rom |
ROM del monitor 1Z-013A |
mz80afi.rom |
ROM AFI (interfaz de disco flexible) del MZ-80A |
mz2000_ipl_*.rom |
ROMs IPL del MZ-2000 (original, TZPU, FusionX) |
mz800_*.rom |
ROMs de sistema del MZ-800 |
msbasic_*.mzf |
MS BASIC para cada objetivo |
sa-5510_tzfs.mzf |
SA-5510 BASIC con soporte TZFS |
sharpmz-test.mzf |
MZF de prueba de hardware |
Que es CI/CD? La integracion continua (CI) es una practica en la que un servidor dedicado compila automaticamente tu proyecto cada vez que envias cambios de codigo. En lugar de ejecutar manualmente el ensamblador en tu maquina de desarrollo, empaquetar los archivos ROM y subirlos a una pagina de descargas, un servidor CI hace todo esto automaticamente. Si la compilacion se rompe — por ejemplo, debido a un error de sintaxis o a un archivo de inclusion faltante — recibes una notificacion por correo electronico de inmediato. Esto detecta los problemas temprano y asegura que cada version publicada se construyo a partir de un punto de partida limpio y reproducible.
Los ROMs de RFS se compilan como parte del pipeline de CI de Jenkins de FusionX. Jenkins es un popular servidor de automatizacion de codigo abierto que se ejecuta en un VPS (servidor privado virtual) o en cualquier maquina Linux. Vigila el repositorio de Gitea en busca de envios a la rama
Como funciona
master y dispara automaticamente una compilacion completa de todos los componentes del proyecto.
El proceso de compilacion automatizado para RFS sigue estos pasos:
- Envias codigo a la rama
masterdel repositorio de Gitea. - Gitea envia un webhook (una notificacion HTTP) al servidor Jenkins.
- Jenkins clona el repositorio en un espacio de trabajo nuevo y limpio.
- Jenkins ejecuta
./build.sh --asmque ensambla todos los ROMs del monitor Z80 y los archivos MZF usando el ensamblador GLASS. - Jenkins empaqueta los archivos ROM y MZF ensamblados en un tarball versionado (
FusionX-ROMs-v1.08.tar.gz). - Jenkins crea una Release de Gitea con el tarball adjunto como un recurso descargable.
- Jenkins envia un correo electronico informando del exito o el fallo.
Todo el proceso tarda alrededor de un minuto y no requiere intervencion manual despues del envio inicial.
Configurar Jenkins
Jenkins se ejecuta dentro de un contenedor Docker para facilitar la instalacion y la portabilidad. Los requisitos minimos son un servidor Linux con 2 GB de RAM, Docker instalado y acceso de red a tu repositorio de Gitea. En tu servidor:
# Install Docker (Debian/Ubuntu) sudo apt update && sudo apt install -y docker.io docker-compose sudo systemctl enable docker && sudo systemctl start docker # Create the Jenkins directory sudo mkdir -p /srv/jenkins/data cd /srv/jenkins
Crear un archivo
docker-compose.yml:
# /srv/jenkins/docker-compose.yml
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts
ports:
- "8080:8080"
volumes:
- /srv/jenkins/data:/var/jenkins_home
environment:
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false
restart: unless-stopped
# Start Jenkins docker-compose up -d # Get the initial admin password (first run only) docker-compose logs jenkins | grep "initial admin password" -A 2 # Open http://your-server:8080 in a browser
En el primer arranque, Jenkins solicita la contrasena de administrador que se muestra en los registros. Tras iniciar sesion, instalar los "plugins sugeridos" y luego anadir el plugin Generic Webhook Trigger mediante Manage Jenkins -> Plugins -> Available.
Crear el pipeline
Un trabajo "Pipeline" de Jenkins se define mediante un script Groovy que le indica a Jenkins exactamente que comandos ejecutar. Para crear un pipeline de compilacion de RFS:
- Hacer clic en New Item en el panel de Jenkins.
- Introducir un nombre (p. ej.
RFS-Build), seleccionar Pipeline, hacer clic en OK. - En la seccion Pipeline, establecer Definition en "Pipeline script" y pegar esto:
pipeline {
agent any
environment {
GITEA_URL = "https://git.eaw.app"
REPO_URL = "https://git.eaw.app/eaw/tzpuFusionX.git"
GITEA_TOKEN = credentials('gitea-api-token')
GITEA_OWNER = "eaw"
GITEA_REPO = "tzpuFusionX"
}
triggers {
GenericTrigger(
genericVariables: [[key: 'ref', value: '$.ref']],
causeString: 'Triggered by Gitea push to $ref',
token: 'rfs-build-trigger',
regexpFilterText: '$ref',
regexpFilterExpression: '^refs/heads/(main|master)$'
)
}
stages {
stage('Checkout') {
steps {
cleanWs()
git url: "${REPO_URL}", branch: 'master'
sh 'git submodule update --init --recursive'
}
}
stage('Build Assembly ROMs') {
steps {
sh 'chmod +x build.sh && mkdir -p software/tmp software/roms'
sh './build.sh --asm'
}
}
stage('Package') {
steps {
script {
def ver = readFile('VERSION').trim()
sh "cd software/roms && tar czf ../../FusionX-ROMs-v${ver}.tar.gz *.rom *.mzf"
archiveArtifacts artifacts: "FusionX-ROMs-v${ver}.tar.gz"
}
}
}
}
post {
success { mail to: 'your-email@example.com', subject: "RFS Build - SUCCESS", body: "Build completed." }
failure { mail to: 'your-email@example.com', subject: "RFS Build - FAILED", body: "Check console output." }
always { cleanWs() }
}
}
Este es un pipeline simplificado que compila solo los ROMs de ensamblador Z80. Para el pipeline completo de FusionX — que tambien compila TZFS, CP/M, modulos del kernel, bitstreams de CPLD y crea releases de Gitea — vease la seccion Guia del desarrollador FusionX — Integracion continua. Esa guia tambien cubre la configuracion del compilador cruzado ARM, la instalacion de Docker de Quartus, la traduccion de rutas de contenedores hermanos y el script de pipeline completo.
Webhook de Gitea
Un webhook le indica a Gitea que notifique a Jenkins cada vez que se envia codigo. En tu repositorio de Gitea, ir a Settings -> Webhooks -> Add Webhook -> Gitea y establecer:
- Target URL:
http://your-server:8080/generic-webhook-trigger/invoke?token=rfs-build-trigger - Content Type:
application/json - Trigger On: Push Events
Tras guardar, enviar un commit a
master y comprobar Jenkins — deberia aparecer automaticamente una nueva compilacion. Hacer clic en el numero de compilacion y luego en Console Output para ver el progreso en tiempo real.
Enlaces de referencia
| Recurso | Enlace |
|---|---|
| Pagina del proyecto RFS | /es/sharpmz-upgrades-rfs/ |
| Manual del usuario RFS | /es/sharpmz-upgrades-rfs-usermanual/ |
| Guia tecnica RFS | /es/sharpmz-upgrades-rfs-technicalguide/ |
| Galeria RFS | /es/sharpmz-upgrades-rfs-gallery/ |
| Guia del desarrollador SFD-700 mkII | /sfd700-developersguide/ |
| Guia del desarrollador picoZ80 | /es/picoz80-developersguide/ |
| Guia del desarrollador FusionX | /tranzputer-fusionx-developersguide/ |
| Ensamblador GLASS Z80 | Incluido en tools/glass-0.5.1.jar |
| Manual CPU Zilog Z80 | Hoja de datos estandar — temporizacion de bus, conjunto de instrucciones, referencia de registros |
| Guia de adaptacion CP/M 2.2 | Digital Research — referencia de diseno CBIOS |