Arquitectura del Z80 (Parte I)
por
- 02/03/2008 a las 21:27 (7484 Visitas)
Vamos a hablar un poco del "cerebro" de la Master System: el Z80. Si bien algunos términos quizá sean algo técnicos o sea de muy bajo nivel, he procurado dar algunas explicaciones que para quien controla del tema serán superfluas, pero pretenden ayudar un poco a quien todo esto le suene a chino pero tenga interés en aprender. Si algo no queda claro, please, avisadme en los comentarios para intentar explicarlo
El Zilog Z80 es un micro catalogado a veces como de 8 bits (todavía no entiendo en base a qué se hace ese tipo de catalogaciones, pero bueno), poseyendo un bus de direcciones de 16 bits y un bus de datos de 8 bits.
Veamos un esquema explicativo:
Como podemos ver, contamos con los siguientes registros accesibles:
- B, C, D, E, H, L y B', C', D', H', L'. Estos registros son de 8 bits, pero pueden agruparse por pares en registros de 16 bits de la forma BC, DE, HL y B'C', D'E', H'L'. Tienen la particularidad de que solo son accesibles a la vez 6 de ellos, pues están divididos en 2 bancos intercambiables por medio de unas instrucciones.
- A, F y A', F'. Como en el caso anterior se trata de registros de 8 bits de los que solo dos son accesibles al mismo tiempo por estar divididos en bancos. El registro A es el acumulador que, como podemos ver en el gráfico, siempre será unos de los operandos de la ALU (Unidad Aritmético Lógica). Por su parte, en el registro F se encuentran los flags de la máquina que guardan su estado.
- PC. Contador de programa, apunta a la dirección de la siguiente instrucción a ejecutar, por lo tanto tiene que ser de 16 bits.
- SP. Puntero de pila, apunta a la primera dirección libre de la pila de ejecución, por tanto es necesario que también sea de 16 bits.
- IX e IY. Estos dos registros de 16 bits se usan como dirección base para instrucciones que hacen uso de vectores. Como podemos ver, existe una mini ALU que solo sirve para sumarle un dato de 8 bits a estos registros y volcar el resultado al bus de direcciones.
- I. Este registro de 8 bits se usa para el tratamiento de interrupciones.
- R. Este registro de 8 bits se usa como salida para refrescar memorias externas.
A su vez el registro F se divide en:
- Bit 7: Flag S. Es el flag que indica el signo, es decir, una copia del bit más significativo de la última operación de la ALU.
- Bit 6: Flag Z. Este flag indica si el resultado de la última operación es cero.
- Bit 5: Flag 5. Este bit en algunos documentos dicen que tiene un valor aleatorio, pero en otros he leído que guarda una copia del bit 5 del resultado de la última operación.
- Bit 4: Flag H. Guarda el acarreo del bit 3 al 4 de la operación (supongo que será útil para operaciones en BCD).
- Bit 3: Flag 3. Este bit en algunos documentos dicen que tiene un valor aleatorio, pero en otros he leído que guarda una copia del bit 3 del resultado de la última operación.
- Bit 2: Flag P/V. Dependiendo de la operación, en este bit se muestra si el resultado tiene paridad par (existe un número par de 1s en el registro) o bien hubo desbordamiento.
- Bit 1: Flag N. Se activará si la última operación fue una resta.
- Bit 0: Flag C. Es el bit de acarreo, se activará si el resultado de la operación no entra en el registro.
Por otro lado, hay otros registros temporales como W y Z que se utilizan para operaciones internas a las instrucciones y, de momento, no he visto que me vayan a ser de utilidad (programaré el resultado final sin hacer uso de ellos a menos que sea necesario).
Una vez visto esto, cabría plantearse cómo implementarlo dentro del emulador.
Mi idea es agruparlo todo, junto a otra información de estado (como los biestables IFF1 y IFF2 que controlan las interrupciones) que vaya viendo más adelante, dentro de una misma estructura de datos. Con esta agrupación sería muy sencillo cargar o salvar el estado interno, útil para transmitir esa información a otra aplicación (como la GUI de la que hablé en la entrada anterior) o bien para los famosos savestates de las partidas.
La siguiente pregunta que me hice fue: ¿qué sería más conveniente para almacenar los registros de 8 bits que pueden agruparse en pares? ¿un tipo de 8 o 16 bits?
La respuesta es sencilla: ambos. En C existe un tipo de estructuras llamadas union en las que puedes declarar varios tipos que comparten la memoria de dicha estructura, es decir, en una estructura union de 16 bits se podría acceder a los 16 bits de golpe (por ejemplo si fuera el par DE) o bien a los 8 bits superiores (D) o los 8 bits inferiores (E).
Creo que esto es suficiente por hoy, mañana, si tengo tiempo, más.