En ocasiones, al hacer romhacking y traducciones, se modifican punteros o textos que luego van a parar a la memoria. En algunos casos hay datos que tienen que tener una cierta alineación en memoria. Si no están alineados correctamente, pueden bloquear el hardware real (la consola) aunque funcionen correctamente en un emulador.
En este artículo se trata el problema de la alineación en la PSX y más concretamente en el Tales of Destiny II/Eternia, que es el caso concreto en el que hemos trabajado.
Inicialmente, el problema de alineación ocurre al modificar punteros a datos de 2 y 4 bytes (short *) y (int *) a punteros datos de 16 y 32 bits conocidos en los procesadores MIPS como "Half" y "Word" respectivamente. En general, tienen que ver con cualquier operación relacionada con las instrucciones LH y LW (Load Half y Load Word).
Una dirección está alineada a 2 bytes cuando dicha dirección es:
Las 5 definiciones son equivalentes.
Una dirección está alineada a 4 bytes cuando dicha dirección es:
Las 4 definiciones son equivalentes
Al copiar datos de forma rápida se usan punteros de 32 bits y la instrucción LW, en cuyo caso deben estar alineadas las direcciones de memoria usadas a 32 bits y tener una longitud múltiplo de 4.
En el Tales of Eternia los datos de las habitaciones están empaquetados por habitaciones y en cada habitación hay diversos archivos que tienen una alineación de 32 bits.
Los datos de tipo short e int deben estar alineados a 2 y 4 bytes. Los compiladores suelen alinear todos los datos a 4 bytes en el ejecutable para que al cargar en memoria sigan alineados y se puedan acceder igualmente.
Este hecho tiene implicaciones muy importantes que hay que tener en cuenta:
- Cuando busca punteros, tarda bastante en buscar números en las direcciones múltiples de 4. - Las "strings" o cadenas terminadas en \0 están alineadas a 4 bytes dejando bytes \0 libres para la alineación. Suponiendo que las cadenas se lean mediante LB (Load Byte) como suele ser normal, se podrá disponer de espacio adicional.
En ciertas circunstancias se usan centinelas de 16 y 32 bits para determinar cuándo termina una secuencia.
En el Tales of Eternia los textos con scripts tinene inserciones de variables o códigos especiales, como por ejemplo escribir un texto mas rápido o mas lento, escribir el nombre de un personaje, la cantidad de dinero, etc.
Estos códigos especiales empiezan por un código de control <= 0x20 y tienen una longitud par. Dicho código puede tener una longitud variable y se utiliza un centinela (una secuencia fija de bytes para conocer el fin de una sucesión). El centinela, pese a ser una sucesión de 32 bits, se comprueba cada 16 bits usando LH un (short *) en C. Para solucionar este problema, en el juego antes de un código de control se usa el caracter 0x1f (caracter dummy) para alinear el texto si la dirección de memoria es impar, es decir, no está alineado a 2 bytes.
Hay una modificación del Emulador PCSX con Debugger integrado que permite comprobar los dos tipos de alineaciones en PSX para saber lo que fallaría en el hardware real.