Programando WHDLoad

### Flujo esquemático de ejecución

La siguiente tabla muestra el flujo del programa cuando un programa instalado con WHDLoad será ejecutado. Espero que ayude a comprender como trabaja WHDLoad y como cooperan WHDLoad, el Esclavo y el programa instalado.

El USUARIO

- arranca la demo o el juego cliqueando en un Icono o arrancando WHDLoad desde la línea de comandos

El Sistema Operativo

- carga el ejecutable de WHDLoad e inicia la ejecución

WHDLoad

- comprueba el entorno de Software y Hardware
- carga y comprueba el Esclavo
- asigna la memoria requerida por el programa instalado
- si Preload/S esta activado, carga las imágenes de disco y los ficheros en RAM (en tanto que haya memoria libre disponible)
- conmuta el SO hacia "apagado" (desactiva la multitarea y las interrupciones, degrada el hardware de gráficos a OCS, inicializa todo el hardware con los valores definidos)
- transfiere la ejecución al Esclavo

Esclavo

- carga el ejecutable principal del programa instalado llamando una función de WHDLoad (tal como resload_DiskLoad o resload_LoadFile)
- parcha el ejecutable principal (para que el programa cargue sus datos utilizando el Esclavo, para solucionar problemas de compatibilidad, o habilitar la función de salir desde el programa)
- transfiere la ejecución al ejecutable principal

Programa Instalado

- hará lo suyo
- al cargar datos desde disco llamara al Esclavo (dado que el Esclavo lo ha parchado para que lo haga previamente), y el Esclavo llamará a WHDLoad, y WHDLoad habilitará parcialmente el SO para cargar los datos (solamente si la información no ha sido Precargada [Preload]), luego retorna, retorna y el programa instalado continúa

El USUARIO

- sale del programa presionando la tecla de salida (QuitKey)

Esclavo

- retorna a WHDLoad llamando la función resload_Abort

WHDLoad

- re-activa el SO (restaura los registros de hardware, visualización y memoria)
- libera todos los recursos asignados
- retorna al SO

### Cómo instalar un lector de pistas simple para un disco

Esta es una pequeña guía paso a paso acerca de como crear un instalador usando WHDLoad. La guía refleja un caso ideal simple. En el mundo real un caso como este probablemente no ocurra nunca. Para casos especiales y problemas, lea los capítulos que siguen a este.

1. Trabajo Previo
   - Cree un directorio que contenga todos los ficheros.
   - Cree una imagen de disco usando DIC en este directorio.
   - Cree un archivo #?.info con "WHDLoad" como <Default Tool> y una Tooltype "SLAVE=#?" conteniendo el nombre del esclavo. (O simplemente copie el icono desde una Instalación Ejemplo, y desactive todas las Tooltypes excepto "SLAVE=").
2. El Esclavo
   Para escribir el esclavo necesitamos la siguiente información:
   1. Dónde esta ubicado el ejecutable principal dentro del disco?
   2. Dónde esta ubicado el programa de carga desde disco dentro del ejecutable principal?
   Para obtener esta información primero analizaremos el sector de arranque. La mayor parte de las veces el ejecutable principal será cargado desde allí usando exec.DoIO(). Algunas veces un lector de pistas especial estará en el sector de arranque. Ahora escribiremos un Esclavo que simule el sector de arranque y cargue el ejecutable principal desde la imagen de disco. Luego extraeremos el ejecutable desde la imagen o un vuelco de memoria. Luego de esto tenemos que encontrar el lector dentro del ejecutable principal. Una forma rápida es buscar el patrón `$AAAAAAAA` (usado por el decodificado MFM) con un editor hexadecimal. Luego corte el área encontrada (+/- `$1000` bytes), desensámblela, y busque el inicio de la rutina. Comprenda la lista de parámetros. Ahora crearemos el código para el Esclavo que parchará esa rutina de carga de tal forma que todas las llamadas al lector sea direccionadas al Esclavo. El Esclavo luego ajustará los parámetros y llamará a la función de WHDLoad resload_DiskLoad.
3. En el caso ideal el instalador estará completo.
   Lo único que falta es crear un bello Icono. Extraiga un par de imágenes usando la funcionalidad snoop de WHDLoad y SP o un congelador o U.A.E. y construya el icono. Se recomienda la paleta de 16 colores RomIcon.

### Posibles problemas y casos especiales

#### Lector de pistas no estándar

Algunos programas usan su propio formato de disco. Esto significa que DIC no será capaz de crear las imágenes de disco. Para crear archivos o imágenes desde tales discos se recomienda el uso de RawDIC. Vea la documentación de RawDIC para mas información.

#### Múltiples discos

Si el programa utiliza mas de un disco el esclavo debe redireccionar los accesos a disco al archivo de imagen apropiado. Algunas veces esto no es sencillo. Algunos programas soportan mas de una unidad de discos, de tal forma que debe usarse el numero de unidad para seleccionar el disco. La mayoría de los programas usan un ID (identificador) en cada disco para distinguirlos. En este caso, utilice una variable que mantenga el numero de disco, y en cada acceso al ID de disco (determine tales accesos analizando los parámetros del lector de disco) incremente la variable (si se ha alcanzado el ultimo disco, decreméntela). De esta forma esperamos que el lector leerá el ID una y otra vez hasta que el disco correcto sea insertado. Tal vez haya un cuadro de dialogo del programa pidiendo el disco correcto, en este caso desactívelo.

#### Salvado de la tabla de puntajes

No mucho que decir. Use resload_SaveFile para escribir el área de memoria apropiada al disco. Si lo desea, encríptela un poco para que los perdedores no puedan modificarla demasiado fácilmente. No se recomienda escribir directamente a las imágenes de disco (usando resload_SaveFileOffset), dado que si algo sale mal (por ej. un cuelgue del sistema) es posible que las imágenes resulten dañadas.

#### Salvado del juego en curso

Esto debe manejarse de igual manera que la tabla de puntajes.

#### Accesos al sistema operativo

Desde el momento que el esclavo y el programa instalado se ejecutan, no existirá absolutamente ningún SO, ni será accesible, ni tendrá ningún sentido intentar acceder al mismo! Por lo tanto todo acceso intentado por el programa instalado debe ser desactivado. Si no hay muchos accesos, y los mismos carecen de sentido en el entorno de WHDLoad (tales como exec.Disable() o exec.SuperState()) simplemente cámbielos por NOP (`$4e71`). Si los accesos tienen una función importante (tal como exec.DoIO()), redirecciónelos al Esclavo y emúlelos. Si hay muchos accesos, cree una librería exec.library simple en un área de memoria no usada (inicialice la palabra larga en la dirección `$4`). Ud. puede consultar el código fuente de Oscar.slave, el cual emula exec.AllocMem(). Para detectar accesos al SO, la execbase inicial se configura en `$f0000001` con la intención de que todas las rutinas que usan execbase creen una excepción de error de dirección ("Address Error" exception).
Si hay un uso intensivo de las funciones del SO, use uno de los paquetes kickemu que pueden encontrarse en el paquete whdload-dev. Hay un paquete para Kick 1.3 ('src/sources/whdload/kick13.s') y uno para Kick 3.1 ('src/sources/whdload/kick31.s'). Estos paquetes requieren una imagen de la kickstart original y crearan un entorno de SO completo dentro del espacio de WHDLoad. Consulte también el archivo readme apropiado que se provee para mayor información.

### Problemas comunes de compatibilidad

#### Espacio de direcciones limitado en 68000/68010/68ec020

En estos procesadores el espacio de direcciones esta limitado a 16 MB (`$000000...$ffffff`) debido a que estas CPU's tienen solamente 24 líneas de direcciones. Como resultado, todos los accesos a direcciones mas altas se realizan en los primeros 16 MB ignorando los 8 bits mas significativos. Algunos programas usan estos bits para almacenar datos, o simplemente olvidan borrarlos. En un procesador con el espacio de direcciones completo de 4 GB tales como 68020/680ec30/68030/68040/68060 esto no funcionara, debido a que se accederán las direcciones completas de 32-bits.
Para solucionar esto es necesario parchar estos accesos y redireccionarlos a la dirección apropiada.
Algunas veces la razón de accesos a direcciones extrañas puede ser un puntero sin inicializar. Si este es el caso, ayudara limpiar `$400` - ws_BaseMemSize.

#### Diferentes entornos de pila en cada procesador

El entorno de pila creado por el procesador durante las interrupciones y excepciones son diferentes para distintos miembros de la familia 68k. En el 68000 el entorno de pila es de 6 bytes, excepto para los errores de bus y direcciones. El entorno de pila contiene el SR salvado en (a7) y el PC salvado en (2,a7). En todos los otros procesadores (68010+) el entorno de pila mínimo es de 8 bytes y adicionalmente contiene el numero de vector como una palabra en (6,a7). Este formato de entorno de pila de 4 palabras `$0` se crea para las interrupciones "Trap #xx" en 68010-68060. Los entornos de pila para otras excepciones son diferentes en cada procesador. La instrucción RTE trabaja diferente en el 68000 comparado con el 68010+. En un 68000 simplemente restaura el SR y el PC y continua la ejecución del programa en la dirección interrumpida. En el 68010+ adicionalmente liberara el entorno de pila dependiendo del formato del mismo.
Algunos programas ponen en la pila una dirección (PC) y un SR y luego ejecutan una instrucción RTE. Esto funcionara solamente en un 68000, pero tendrá resultados no definidos en un 68010+.
Si un programa hace esto, habrá que solucionar el problema. Algunas veces alcanza con reemplazar el RTE por RTR.

#### MOVEM.x RL,-(An) en 68000/010 y 68020/030/040

Existe una diferencia si el registro usado en el modo de pre-decremento (RL) esta también contenido en la lista de registros. Para los 68020, 68030 y 68040 el valor escrito a memoria es el valor inicial del registro decrementado por el tamaño de la operación. El 68000 y 68010 escriben el valor inicial del registro (no decrementado).
Dado que tal construcción no seria muy útil, no se conoce ningún software que actualmente tenga problemas debido a esto.

### Lineamientos generales para escribir instaladores

- No modifique los registros de CPU presentes en los procesadores mas altos tales como VBR o CACR. El VBR siempre es 0 desde el punto de vista de los programadores de Esclavos, aun si es movido debido a que los Vectores Automáticos (y Traps si el modificador WHDL_EmulTrap esta configurado) son emulados. Los bits en el CACR son diferentes para cada procesador. Solamente hay una forma valida de modificar las caches, use resload_SetCACR/SetCPU y las bitdef's de 'exec/execbase.i' y 'whdload.i'. Todas las porciones de código presentes en el programa a instalar que modifiquen estos registros deben ser desactivadas o salteadas durante la ejecución, de otra forma WHDLoad no podrá trabajar correctamente!
- Nunca modifique las imágenes de disco. Esto tiene la ventaja de que si alguien desea arrancar el programa desde disco, solamente deberá escribir las imágenes nuevamente al disco (suponiendo que el programa se ejecute sin demasiados parches, seguramente no es el caso mas frecuente).
- Nunca use el soporte original del programa directamente en el esclavo (problemas de derechos de copia).
- Active las Caches solamente si Ud. esta seguro de que funcionara con todos los procesadores.
- Use tan poca memoria como sea posible para ws_BaseMemSize. Alguna gente usa marcadores (tags) residentes al final de la memoria Chip, de modo que ayuda utilizar solamente `$1f0000` en lugar de `$200000` y WHDLoad puede utilizar memoria asignada en forma absoluta.

### Sugerencias & trucos

#### Que es mejor, usar imágenes de disco o ficheros?

Algunas veces Ud. tendrá la oportunidad de elegir usar imágenes de disco o ficheros reales. Ambos tienen sus ventajas. El uso de imágenes de disco es usualmente la forma mas sencilla y rápida de crear el Esclavo. Pero los ficheros reales son mucho mas sencillos de mantener en una caché (si hay poca memoria o la memoria esta fragmentada). El espacio necesario en disco duro también será menor con los ficheros reales que con imágenes de disco. Ud. solo deberá usar imágenes de disco si hay muchos ficheros (mas de 30).