ZX Spectrum
Contenido
- 1 Características
- 2 Diagrama de bloques
- 3 Nuevos registros E/S para control de ZX-Uno
- 4 Modos gráficos disponibles
- 5 Firmwares disponibles
- 6 Layouts de teclado
- 7 Joysticks
- 8 TO DO
- 9 Acceso a los ficheros del core
Características
Diagrama de bloques
El core usa el módulo T80, con un pequeño wrapper para separar el bus de datos en dos: uno de entrada a la CPU (cpudin) y otro de salida desde la CPU (cpudout). Un multiplexor elige qué dato entra a la CPU según el periférico o región de memoria que se esté usando en ese momento, y equivale al bus triestado que existiría en el sistema original. El bus de datos de salida va hasta los demás módulos.
El módulo del manejador de memoria en realidad contiene muchas cosas:
- El gestor de la memoria de doble puerto, que convierte la SRAM de alta velocidad incluida en la placa del ZX-Uno en una memoria de doble puerto, con un puerto de lectura/escritura, y otro independiente de sólo lectura. El primero es de uso exclusivo de la CPU, y el otro de uso exclusivo para la ULA.
- La MMU vertical que proporciona el sistema de bancos de memoria y que implementa el esquema seguido en el Spectrum +2A/+3, que incluye a su vez el esquema del 128K/+2 gris. Esta MMU se ampliará para dar cabida a la MMU horizontal para dar soporte a la paginación compatible con Chloe 280SE.
La ULA es una versión extendida, con los timmings del 48K, pero con soporte para los modos Timex HiColour y HiRes, y ULAplus. Uno de los cores contempla además un modo de pantalla especial, diseñado como parte de un experimento, para dotar al Spectrum de una resolución de 128x96 pixeles, 16 colores de una paleta de 256, y con color independiente para cada pixel.
El módulo SPI alberga un pequeño core que implementa una interfaz SPI que se comparte entre los dos periféricos que usan este protocolo: la SPI flash y la tarjeta SD/MMC. Los chip-enable para cada uno de estos periféricos son antagonistas: si está habilitado uno, se deshabilita automaticamente el otro, para que no haya conflictos. Para la SD/MMC se implementan tanto los puertos DIVMMC como los puertos ZXMMC.
Para controlar todos los nuevos periféricos añadidos a ZX-Uno (en este momento, la SPI Flash, el registro de configuración maestro, y el mapeador de memoria maestro), se usan dos puertos asignados por el comité ZXI. Estos puertos dan lugar a usar hasta 256 registros diferentes de E/S. La dirección del registro aparece en "addr" y la operación (lectura o escritura), en las señales "ior" e "iow".
El mixer es un codificador Sigma-Delta de 8 bits, que mezcla las señales del altavoz, mic, ear y la salida de 8 bits del módulo AY-3-8912. La salida de la mezcla va directamente a la salida de audio.
Los relojes del sistema
La ULA
Generador de sincronismos y señal WSS
El teclado
La memoria
Módulo de multiplexión de la SRAM para obtener una memoria de doble puerto
Mapa de memoria de la SRAM
Sistemas de banking vertical y horizontal
Periféricos SPI
El Z80
El bus de expansión
Nuevos registros E/S para control de ZX-Uno
Se dispone de los puertos $FC3B y $FD3B, asignados por el comité ZXI. A través de estos puertos se accede a un total de 256 registros de E/S diferentes exclusivos para ZX-Uno.
- El puerto $FC3B (64571) guarda la dirección ($00 - $FF) del registro de E/S al que se quiere acceder. Puede leerse para saber cuál es la última dirección de registro asignada.
- El puerto $FD3B (64827) es el puerto de acceso al registro seleccionado con el puerto anterior. Su sentido (lectura/escritura) dependerá de la implementación de cada registro.
Los registros implementados hasta ahora en ZX-Uno son:
Número | Nombre | Sentido | Descripción | Valor tras reset de usuario | Valor tras reset maestro | Valor tras poweron | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$00 | MASTERCONF | Lectura/Escritura | Formato binario (en gris, los campos que sólamente pueden alterarse cuando LOCK=0):
|
No cambia | 00000001 | 00000001 | ||||||||
$01 | MASTERMAPPER | Lectura/Escritura | De este registro sólo se usan sus 5 bits inferiores (valores $00 a $1F). El valor guardado es el número de un banco de 16KB de SRAM que será paginado en las direcciones $C000-$FFFF durante el modo boot. Los valores de este registro no tienen ningún efecto cuando ZX-Uno está en modo ejecución. 32 valores diferentes para este registro permiten direccionar hasta 512KB de SRAM. Si ZX-Uno se amplía con más memoria, se usarán más bits en este registro. La máxima cantidad de memoria manejable es de 4MB. | No cambia | 00000000 | 00000000 | ||||||||
$02 | FLASHSPI | Lectura/Escritura | Puerto de acceso al registro SPI conectado a la SPI Flash. Escribiendo un valor en este registro, se envía a la SPI Flash, si ésta está seleccionada. Leyendo un valor de este registro, se lee el último valor enviado por la SPI Flash, y además, la misma operación de lectura provoca que la SPI envíe un nuevo valor (que sería leído con la siguiente operación de lectura a este registro). Por esta razón, en operaciones de lectura de bloques, el primer byte leído con este puerto debe descartarse. | No cambia | No cambia | 00000000 | ||||||||
$03 | FLASHCS | Lectura/Escritura | Sólo se emplea el bit 0. El valor escrito en este registro determinado el estado de la línea CS de la Flash SPI (0 = Flash seleccionada, 1 = flash no seleccionada) | No cambia | No cambia | 00000001 | ||||||||
$04 | SCANCODE | Lectura/Escritura | En lectura, permite obtener el valor del último scancode generado por el teclado. En escritura permite enviar comandos al teclado. | No cambia | No cambia | No cambia | ||||||||
$05 | KEYSTAT | Lectura | Varios bits que indican si hay o no una nueva tecla pulsada, o soltada, y si ésta es una tecla extendida o normal.
|
No cambia | No cambia | No cambia | ||||||||
$06 | JOYCONF | Lectura/Escritura | Los bits 0 a 2 indican el modo de funcionamiento del joystick mapeado en teclado (o del segundo joystick físico si hay splitter). Los bits 4 a 6 indican el modo de funcionamiento del joystick físico (conector DB-9 lateral). El bit 3 indica el autofuego del segundo joystick o keypad. El bit 7 indica el autofuego del joystick principal. Los valores son: 000 = Disabled, 001 = Kempston, 010 = Sinclair 1, 011 = Sinclair 2, 100 = Protek/Cursor/AGF, 101 = Fuller, 110 = OPQAspM, 111 = reservado. | No cambia | No cambia | 00100001 | ||||||||
$07 | KEYMAP | Lectura/Escritura | En lectura, cada acceso proporciona el siguiente byte del mapa de teclado cargado en ZX-Uno actualmente. En escritura, el byte correspondiente al mapa de teclado marcado por la posición actual es modificado. En ambos casos, el puntero de direcciones se incrementa automáticamente para señalar al siguiente byte del mapa de teclado. Este puntero vuelve a 0 automáticamente tras un reset, una escritura en el registro $FC3B, o cuando se termina el mapa de teclado. El mapa de teclado, en la implementación actual, ocupa 16384 bytes. | Ver descripción | Ver descripción | Ver descripción | ||||||||
$09 | MOUSEDATA | Lectura/Escritura | Registro de datos del puerto PS/2 del ratón. Usado para leer o enviar comandos directos al ratón PS/2. Por ejemplo: para inicializar el ratón, debe enviarse el valor $F4 a este registro. | No cambia | No cambia | No cambia | ||||||||
$0A | MOUSESTATUS | Lectura/Escritura | Registro de estado del puerto PS/2 del ratón. Se definen los siguientes bits:
|
No cambia | No cambia | No cambia | ||||||||
$0B | SCANDBLCTRL | Lectura/Escritura | Registro de control del scandoubler y control de la velocidad del sistema. Se definen los siguientes bits:
|
No cambia | No cambia | 00000000 | ||||||||
$0C | RASTERLINE | Lectura/Escritura | Almacena los 8 bits menos significativos de la línea de pantalla en la que se desea provocar un disparo de una interrupción enmascarable. Un valor 0 para este registro (con LINE8 también igual a 0) establece que la interrupción ráster se disparará, si está habilitada, justo al comenzar el borde derecho de la línea anterior a la primera línea de pantalla en la que comienza la zona de "paper". Dicho en otras palabras: el conteo de líneas de esta interrupción asume que una línea de pantalla se compone de: borde derecho + intervalo de blanking horizontal + borde izquierdo + zona de paper. Si se asume de esta forma, el disparo de la interrupción se haría al comienzo de la línea seleccionada.
Un valor para RASTERLINE igual a 192 (con LINE8 igual a 0) dispara la interrupción ráster al comienzo del borde inferior. Los números de línea para el fin del borde inferior y comienzo del borde superior dependen de los timings empleados. El mayor valor posible en la práctiva para RASTERLINE corresponde a una interrupción ráster disparada en la última línea del borde superior (ver RASTERCTRL) |
11111111 | 11111111 | 11111111 | ||||||||
$0D | RASTERCTRL | Lectura/Escritura | Registro de control y estado de la interrupción ráster. Se definen los siguientes bits.
|
00000001 | 00000001 | 00000001 | ||||||||
$0E | DEVCONTROL | Lectura/Escritura | Registro de habilitacion/deshabilitacion de distintas caracteristicas. Se definen los siguientes bits.
|
No cambia | 00000000 | 00000000 | ||||||||
$0F | DEVCTRL2 | Lectura/Escritura | Registro de habilitacion/deshabilitacion de distintas caracteristicas (continuación de DEVCONTROL). Se definen los siguientes bits.
|
No cambia | 00000000 | 00000000 | ||||||||
$10 | MEMREPORT | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$40 | RADASCTRL | Lectura/Escritura | Registro para establecer el modo radastaniano y establecer sus características. Las escrituras a este registro son ignoradas si el bit correspondiente en DEVCTRL2 está activo. Se definen los siguientes bits
|
00000000 | 00000000 | 00000000 | ||||||||
$41 | RADASOFFSET | Lectura/Escritura | Contiene el número de bytes que hay que añadir a la dirección base de la pantalla (4000h, 6000h, C000h o E000h según la configuración) para obtener la dirección donde se encuentran los dos primeros píxeles en modo radastaniano. Es un registro de 14 bits. Para escribir un valor, primero se escriben los 8 bits menos significativos, seguidos inmediatamente de los 8 bits más significativos (los 2 bits más significativos de este valor se ignoran).
Si el valor de offset es tal que hace que al explorar la memoria de pantalla para crear la imagen se llegue al final de una página de 16KB, la exploración continuará al principio de esa misma página. |
00000000 | 00000000 | 00000000 | ||||||||
$42 | RADASPADDING | Lectura/Escritura | Contiene el número de bytes - 64 que ocupa un scanline en modo radastaniano. Es decir, si este registro vale 0, la longitud en bytes de un scanline es de 64 bytes (128 pixeles). Si este registro vale 4, la longitud de un scanline es de 68 bytes (136 píxeles). Si vale 255, la longitud de un scanline es de 64+255=319 bytes, o 638 píxeles.
Si el valor de offset es tal que hace que al explorar la memoria de pantalla para crear la imagen se llegue al final de una página de 16KB, la exploración continuará al principio de esa misma página. |
00000000 | 00000000 | 00000000 | ||||||||
$43 | RADASPALBANK | Lectura/Escritura | Registro para establecer qué sección de la paleta de ULAplus se usará para definir los colores en el modo radastaniano, y cómo se comportará el borde.
|
00000000 | 00000000 | 00000000 | ||||||||
$80 | HOFFS48K | Lectura/Escritura | Valor de ajuste de centrado horizontal de la pantalla para la ULA de 48K | No cambia | No cambia | $38 | ||||||||
$81 | VOFFS48K | Lectura/Escritura | Valor de ajuste de centrado vertical de la pantalla para la ULA de 48K | No cambia | No cambia | $01 | ||||||||
$82 | HOFFS128K | Lectura/Escritura | Valor de ajuste de centrado horizontal de la pantalla para la ULA de 128K | No cambia | No cambia | $3A | ||||||||
$83 | VOFFS128K | Lectura/Escritura | Valor de ajuste de centrado vertical de la pantalla para la ULA de 128K | No cambia | No cambia | $01 | ||||||||
$84 | HOFFSPEN | Lectura/Escritura | Valor de ajuste de centrado horizontal de la pantalla para la ULA de Pentagon | No cambia | No cambia | $37 | ||||||||
$85 | VOFFSPEN | Lectura/Escritura | Valor de ajuste de centrado vertical de la pantalla para la ULA de Pentagon | No cambia | No cambia | $00 | ||||||||
$A0 | DMACTRL | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$A1 | DMASRC | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$A2 | DMADST | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$A3 | DMAPRE | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$A4 | DMALEN | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$A5 | DMAPROB | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$A6 | DMASTAT | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$C6 | UARTDATA | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$C7 | UARTSTAT | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$C8 - $DF | RESERVED | Lectura/Escritura | Rango de registros de ZXUNO reservados para experimentos o uso privado | Definido por el usuario | Definido por el usuario | Definido por el usuario | ||||||||
$F0 | SRAMADDR | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$F1 | SRAMADDRINC | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$F2 | SRAMDATA | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$F3 | VDECKCTRL | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$F7 | AUDIOMIX | Lectura/Escritura | Control de la mezcla de los canales izquierdo/derecho partiendo de los 4 canales del AY-8912. Se definen los siguientes grupos de 2 bits cada uno:
|
No cambia | No cambia | 10011111 | ||||||||
$FB | AD724 | Lectura/Escritura | Control del modo de funcionamiento del chip encoder AD724. Se definen los siguientes bits:
|
No cambia | No cambia | 00000000 | ||||||||
$FC | COREADDR | Lectura/Escritura | Almacena la dirección, dentro de la memoria SPI, de inicio del core a arrancar. Para almacenar una dirección diferente, se han de realizar tres escrituras a este registro, conteniendo los tres bytes de la dirección, en orden de más a o menos significativo. En lectura, cada acceso a este registro devuelve una parte de la última dirección almacenada, de la parte más significativa a la menos significativa. | No cambia | No cambia | $058000 | ||||||||
$FD | COREBOOT | Escritura | Registro de control de arranque. Escribiendo un 1 en el bit 0 de este registro (el resto de bits están reservados y deben quedarse a 0) hace que se desencadene el mecanismo interno de la FPGA que permite arrancar otro core. La dirección de comienzo de este segundo core será la última que se escribiera usando el registro COREADDR. | No cambia | No cambia | No cambia | ||||||||
$FE | SCRATCH | Lectura/Escritura | No cambia | 00000000 | 00000000 | |||||||||
$FF | COREID | Lectura | Cada operación de lectura proporciona el siguiente carácter ASCII de la cadena que contiene la revisión actual del core del ZX-Uno. Cuando la cadena termina,lecturas posteriores emiten bytes con el valor 0 (al menos se emite uno de ellos) hasta que vuelve a comenzar la cadena. Este puntero vuelve a 0 automáticamente tras un reset o una escritura en el registro $FC3B. Los caracteres entregados que forman parte de la cadena son ASCII estándar imprimibles (códigos 32-127). Cualquier otro valor es indicativo de que este registro no está operativo. | Ver descripción | Ver descripción | Ver descripción |
Por ejemplo, para asignar el banco 16 de la SRAM al espacio de direcciones $C000 - $FFFF durante el modo boot, mediante el registro MASTERMAPPER, se haría así:
ld bc,$fc3b ;Puerto para establecer el número de registro a usar ld a,1 ;Registro $01 (MASTERMAPPER) out (c),a ;Se selecciona. A partir de ahora, cualquier acceso a $FD3B está usando MASTERMAPPER inc b ;Puerto de acceso al registro ($FD3B, basta con incrementar B) ld a,16 ;Banco 16 de la SRAM out (c),a ;Se escribe en el registro MASTERMAPPER
Modos gráficos disponibles
Firmwares disponibles
Layouts de teclado
El módulo que se encarga de gestionar el teclado está gobernado por una tabla en la que se especifica, para cada scancode recibido desde el teclado PS/2, qué tecla o combinación de teclas del teclado del Spectrum le corresponde.
El usuario puede crear y cargar mapas de teclado en la memoria de la FPGA, alterando así la forma en la que el teclado PS/2 se comporta respecto del core de Spectrum. Los mapas sólo afectan a este core, lo que incluye la BIOS.
A partir del core EXP26, el mapa de teclado se compone de un par de vectores: keymap1 y keymap2, cada uno de 2048 posiciones x 8 bits. Cada posición se corresponde con una posible pulsación de tecla en el teclado PS/2, de acuerdo al siguiente esquema:
10 | 9 | 8 | 7 | 6 a 0 |
ALT | CTRL | SHIFT | EXT | SCANCODE |
Los bits 10, 9 y 8 de la dirección indican si esa tecla se ha de pulsar en combinación con alguna de las teclas modificadoras: Shift, Control, o Alt. Hay 8 combinaciones posibles a aplicar en una tecla.
El bit 7 indica si el scancode de la tecla es un scancode extendido (el teclado envía E0 antes del scancode)
Los bits 6 a 0 son el scancode de la tecla. El mapa sólo admite teclas cuyo scancode (extendido o no) esté en el rango 00h a 7Fh. En un teclado estándar, esta restricción sólo afecta a la tecla F7.
Los vectores keymap1 y keymap2 contienen, cada uno, 8 bits en cada elemento, con el siguiente formato:
7 a 5 | 4 a 0 |
ROW | COLUMBITS |
ROW es una de las 8 filas de teclas de la matriz del Spectrum, codificado en binario, donde se encuentra la tecla de Spectrum que debe activarse en respuesta a la tecla PS/2 usada. COLUMBITS es un valor de 5 bits, que se corresponde con el estado de las teclas de la fila seleccionada en ROW. Un bit a 1 indica que la tecla en la posición del bit está pulsada. 0 que no está pulsada.
Usando estos dos vectores, es posible asignar a cada pulsación de tecla del teclado PS/2, 0, 1 o 2 pulsaciones del teclado del Spectrum. Ejemplo: si en el teclado PS/2 se pulsa la tecla +, en el teclado de Spectrum debe pulsarse SYMBOL SHIFT y K
En el teclado inglés, la tecla + se obtiene pulsando SHIFT y la tecla =, cuyo scancode es 55h no extendido (1010101 en binario). Esto significa que en la dirección de vector 001 0 1010101 (esto es, modificador SHIFT a 1, EXT a 0, y scancode 55h) se almacenará la pulsación de SYMBOL SHIFT y la pulsación de K. La primera pulsación se almacenará en keymap1 y la segunda, en keymap2.
Dirección | keymap1 | keymap2 |
001 0 1010101 | 111 00010 | 110 00100 |
Las teclas que sólo requieran de una pulsación en la matriz del Spectrum, almacenarán en keymap2 el valor 00000000.
Es posible usar uno de los vectores y aún así especificar la pulsación de más de una tecla, si se da el caso de que ambas teclas están en la misma fila. Ejemplo: si en el teclado PS/2 se pulsa el punto ( . ) , en el Spectrum esa pulsación se corresponde con SYMBOL SHIFT + M. Como estas dos teclas están en la misma semifila, es posible especificarlas de una vez, así:
Dirección | keymap1 | keymap2 | Comentarios |
001 0 1001001 | 111 00110 | 000 00000 | En keymap1 se registra tanto la pulsación de SYMBOL SHIFT como de M |
ROW | COLUMBITS | ||||
4 | 3 | 2 | 1 | 0 | |
000 | V | C | X | Z | CAPS SHIFT |
001 | G | F | D | S | A |
010 | T | R | E | W | Q |
011 | 5 | 4 | 3 | 2 | 1 |
100 | 6 | 7 | 8 | 9 | 0 |
101 | Y | U | I | O | P |
110 | H | J | K | L | ENTER |
111 | B | N | M | SYMBOL SHIFT | SPACE |
Joysticks
Hay soporte para 2 joysticks desde el core. El joystick 1 es un joystick físico (puerto DB9 del ZX-Uno) mientras que el joystick 2 es a la vez un joystick virtual generado con el teclado numérico (keypad) y un segundo joystick físico (DB9) disponible en modelos con splitter. Ambos joysticks tienen 2 botones de disparo y se pueden configurar por separado a una de estas 7 normas:
- 000 = Disabled
- 001 = Kempston, segundo disparo bit 5
- 010 = Sinclair 1, segundo disparo tecla X
- 011 = Sinclair 2, segundo disparo tecla Z
- 100 = Protek/Cursor/AGF, segundo disparo tecla 9
- 101 = Fuller, segundo disparo bit 5
- 110 = OPQAspM, segundo disparo tecla M
TO DO
-
Modificar el core del AY-3-8912 (o quizás buscar otro, ya veremos) que me dé los tres canales por separado, para así poderlos mezclar usando el esquema ACB o uno similar. Ahora mismo el sonido que tenemos es monoaural. -
Añadir el tema de las teclas para cambiar de modo de video on-the-fly
Acceso a los ficheros del core
La versión más reciente del core (11/02/2017) es test24. Las características de este core son:
- Implementación ZX Spectrum 48K, 128K, Pentagon y Chloe 280SE
- ULA con modos ULAplus, Timex y modo Radastan
- Scroll hardware en modo Radastan
- Grupo de paleta seleccionable en modo Radastan
- Posibilidad de desactivar la contención de memoria (para compatibilidad con Pentagon 128)
- Posibilidad de elegir el comportamiento del teclado (issue 2 o issue 3)
- Posibilidad de elegir el timing de la ULA (48K, 128K o Pentagon)
- Control del encuadre de pantalla configurable para tipo de timing, y posibilidad de elegir entre sincronismos originales de Spectrum o sincronismos estándar PAL progresivo.
- Soporte de la MMU horizontal del Timex con bancos HOME, DOC y EXT en RAM.
- Interrupción ráster programable en número de línea, para cualquier linea de TV.
- Posibilidad de activar/desactivar los registros de manejo de bancos de memoria, para mejor compatibilidad con cada modelo implementado
- Posibilidad de activar/desactivar los dispositivos incorporados al core para mejorar la compatibilidad con ciertos programas
- Soporte ZXMMC para +3e
- Soporte DIVMMC para ESXDOS, UnoDOS, y firmwares compatibles
- Soporte Turbo Sound
- Soporte de SpecDrum
- Cada canal A,B,C de los dos chips AY-3-8912, beeper y SpecDrum pueden dirigirse a las salidas izquierda, derecha, ambas o ninguna, permitiendo la implementación de configuraciones tales como ACB, ABC, etc.
- Soporte de joystick real y joystick en teclado con protocolo Kempston, Sinclair 1 y 2, Cursor y Fuller.
- Soporte de modo turbo a 7MHz y 14MHz
- Soporte de teclado con protocolo PS/2 y mapeado configurable por el usuario desde el propio Spectrum.
- Soporte de ratón PS/2 emulando el protocolo Kempston Mouse.
- Posibilidad de salida de video en modo de video compuesto, RGB 15kHz, o VGA.
- Frecuencia de refresco vertical seleccionable por el usuario para mejorar la compatibilidad con monitores VGA.
- Soporte de arranque multicore: desde el Spectrum se puede seleccionar una dirección de la SPI Flash y la FPGA cargará un core desde ahí.