Y qué puede haber más apropiado que un simple zx80 que está basado completamente en electrónica discreta.
En los ratos libres que tengo me he puesto manos a la obra y después de intentar entender la rutina de display de la ROM y el funcionamiento del hardware (menuda marcianada que se curró el diseñador ), he copiado el esquema y ya tengo enrutada la placa.
Me he tomado la libertad de sustituir los dos chips de 1K x 4bits de RAM por unos solo de 32K x 8bits, y la ROM de 8Kb por una EPROM de 32Kb que es mucho más barata y con alguna sencilla modificación podría convertir el ordenador en un "2 en uno", ZX80, ZX81. Aunque sobra espacio, es más barata una EPROM de 32Kb que una de 16Kb.
También he sustituido el teclado de membrana por pulsadores manteniendo la posibilidad de añadir una membrana original, y manteniendo exactamente el tamaño de la placa original, pero reenrutando todo para que el resultado sea una placa de sólo dos capas.
Quizás no sea un enfoque tan purista como el de Antonio, pero a mi me sirve como ejercicio práctico para continuar aprendiendo, e incluso encaja exactamente en una caja original (El próximo objetivo sería fabricar una caja identica a la original, ya sea con una impresora o por vacuoformado).
Aquí os dejo el esquema y como quedaría la placa principal.
Y aqui la placa auxiliar que se conecta al bus trasero y que le da las nuevas funcionalidades.
https://goo.gl/photos/HCjJ5Z9i7Pd1rETW8
El listado de componentes lo podéis encontrar aquí:
Aquí os dejo los fallos que he encontrado hasta ahora y que tendréis que corregir en primer lugar:
Seguidamente las modificaciones que hay que hacer para eliminar la ampliación del zx81 y dejar la placa exactamente igual que el zx80:Conectar el pin central del cristal a masa
Girar 180º el 7805
No soldar D11
No soldar R43
Conectar /WR en la patilla 27 de la RAM
Conectar /WAIT a +5V con una resistencia de 1K
Desconectar el HALT de R23 pero manteniendo conectada la señal HALT con el pin 3 de IC16
C15 es de 220pF
Para facilitar la faena de montaje y el repaso del circuito, aquí os dejo los esquemas y la placa que se ha mandado fabricar en eagle:Quitar U1, U2, U3, U4, U5, U6
Unir IC11.10 con IC11.11
Unir IC13.10 con IC16.10
Unir IC19.5 con R32 patilla derecha y con IC21.1
Poner JP3 en 1-2
Poner JP1 en 2-3
Para usar el LM
Poner JP6 en 2-3
Poner JP5
Para usar el video del zx80
Poner JP6 en 1-2
Quitar JP5
La placa funciona como un zx80, pero tiene selector para poder convertirlo en un zx81.
Otra modificación que tiene es que genera el black porch con un circuito de jose_leandro para que no pase como en el original que no se ve con las teles modernas.
La parte del teclado permite dos opciones:
- Soldar microswitches
- Acoplar una membrana de zx80, gracias al entramado que he añadido en la parte interior de la huella de los microswitches.
Los anclajes y agujeros encajan perfectamente con los de la caja del zx80 real, por lo que se podría poner dentro de una de estas cajas, aunque como estas son prácticamente imposibles de conseguir alvaroalea está trabando en un diseño para impresora 3D
Como alternativa hay un método (vacuformado) que parece prometedor y que ha propuesto groovydrifter :
Y aquí una interpretación de como funciona el hardware.
La interpretación la he hecho basándome en el esquema publicado aquí y el listado en ensamblador de la ROM que se puede encontrar aquí.
La explicación viene dividida según las partes lógicas en las que podemos dividir el hardware.
Generador de NOPs
El circuito siguiente es el que se encarga de comprobar que estamos refrescando la pantalla.
La salida del circuito (patilla 6 de IC16) es igual a 0 cuando /HALT = 1, A15 = 1 y D6=0, osea siempre y cuando no estemos ejecutando un HALT (/HALT y D6=0) y estemos ejecutando algo en la segunda mitad de la memoria (A15=1), que como ya habíamos dicho solo ocurre cuando refrescamos la pantalla. Al comprobar que /HALT = 1 y D6 = 0 descartamos también el momento en el que ya hemos llegado a fin de línea.
La salida de este circuito va a parar al pin 9 de IC 17 (ver abajo) lo que hace que sólo tengamos un 0 a la salida de este “OR” (patilla 8 de IC 17) en el caso de que el circuito anterior sea 0 y /M1=0, es decir estemos pintando la pantalla y estemos en el ciclo de fetch.
Al tener un 0 en el pin 8 de IC 17 tendremos un 1 en el pin 2 de IC 15, lo que hará 0 todos los bits de datos (D0..D7) conectados al conjunto de NOPs de la figura de arriba.
Secuencia de visualización de video
IC5 es un circuito 74LS373 que consta de 8 latchs triestado. En este caso tenemos siempre a 0 la habilitación (patilla 1) por lo que los latch se utilizan como biestables.
Dicho circuito es el que se encarga de capturar cada código de carácter que es puesto es el bus de datos por la CPU cuando se está en la fase de refresco de pantalla. Estos datos acaban en el bus, ya que la CPU está ejecutando la zona correspondiente a DFile y por tanto poniendo el contenido de dicha memoria en el bus de datos, aunque como dijimos antes sólo se ejecutan NOPs ya que estos datos son sustituidos por ceros en la fase fetch.
En dicho circuito, capturamos únicamente los bits D0..D5 que son los 64 caracteres posibles y D7 que nos indica si hay que invertir el vídeo.
La patilla 11 (LE) que es activa en alta, es la que deja o no pasar los datos desde el bus de datos.
La patilla 11 se activa cuando alcanzamos la fase de RFSH, teniendo a uno la salida del circuito siguiente (patilla 4 de IC13):
La salida de IC5 es redirigida a los tres chips multiplexores IC6, IC7 e IC8 que seleccionan entre un acceso a ROM estándar o un acceso a la ROM de caracteres cuando estamos en la fase de refresco. La señal de selección (S) de dichos chips está conectada directamente a /RFSH, por lo que cuando /RFSH = 0 se seleccionan las entradas que llegan desde IC5, interpretando el código presente en el bus de datos como una dirección que apunta a la tabla de caracteres en ROM.
La correspondencia es como sigue:
D0 -> A3, D1 –> A4, D2 –> A5, D3 –> A6, D4 –> A7, D5 –> A8.
Estos 6 bits nos direccionan el carácter dentro de la tabla de caracteres.
El scanline del carácter a representar viene determinado por los tres bits inferiores, por lo que las 3 líneas inferiores se alimentan de un contador de 3 bits que reside en IC21 y que va contando cíclicamente al compás del sincronismo horizontal los 8 scanlines de cada carácter, y es reseteado cuando se dispara el sincronismo vertical.
Con lo anterior tenemos la dirección correspondiente al desplazamiento dentro de la tabla de caracteres del scanline a representar, pero nos falta añadir la dirección de tabla dentro de la ROM.
Los bits A9, A10 y A11 que nos faltan vienen directamente del bus de direcciones debido que estamos en el ciclo de refresco y en el programa de la ROM (antes de activar las interrupciones) hemos cargado convenientemente el registro I para que apunte a la tabla de caracteres en ROM:
Código: Seleccionar todo
LD A,$0E ; set the I register to $0E to tell
LD I,A ; the video hardware where to find
; the character set ($0E00).
Por otro lado, el valor que entra de D7 en IC5, va a parar al circuito que controla la inversión del vídeo de los caracteres.
Este dato entra por la patilla 5 de IC11 acabando en un OR exclusivo con el dato serializado que viene por la patilla 4 de IC20, por lo que si D7 está a 1 el dato que llega se invertirá.
serialización de los datos de video.
La serialización la realiza IC9.
Se utiliza un reloj de 6,5MHz que le llega directamente del cristal. Este reloj entra por el pin 2.
La salida es normalmente el pin 7 (/Q) produciendo un video de caracteres blancos sobre fondo negro, pero puede modificarse utilizando el pin 9 (Q).
El pin 1 (S/L) habilita la serialización, permitiendo que fluyan los datos sólo cuando el pin 9 de IC5, que es un flip-flop, es igual a cero. Esto ocurre cuando estamos en la fase de refresco de pantalla indicado por el circuito de la página anterior (patilla 6 de IC16)
Los datos vienen desde el circuito que multiplexa el acceso a la ROM entre la CPU o el sistema de visualización. Este circuito está formado por los chips IC6, IC7 e IC8.
La visualización vista desde el lado del Z80.
Lo primero que llama la atención en el esquema es que /INT está conectado directamente con A6, eso significa que la línea correspondiente a la activación de las interrupciones enmascarables se activa simplemente accediendo a cualquier dirección cuyo bit 6 sea 0.
Leyendo el listado de la ROM del Z80, cuando echas un vistazo a la rutina de servicio de interrupciones, lo que te encuentras es que se carga en HL la dirección de la zona de pantalla+32Kb, inmediatamente después se activan las interrupciones con la instrucción “EI” y después hace un salto incondicional a dicha dirección, como si de un trozo de programa se tratara.
El hardware monitoriza la señal A15, por lo que todo acceso a una posición de memoria superior a 32Kb el sistema lo interpreta como que se está refrescando la pantalla y en lugar de meter en el bus de datos el contenido de la memoria, durante la fase de fetch, mete en dicho bus un 0, que es el código de la instrucción NOP o “No Operation”.
El programa continúa ejecutando NOPs hasta que se encuentra con una instrucción HALT en la memoria (en los zx80 y 81 se utiliza un HALT o $76 como fin de línea), momento en el cual el hardware deja pasar dicha instrucción y deja al procesador parado hasta que se active /INT. (La comprobación de si es una instrucción HALT la hace el hardware comprobando si el bit 6 del bus de datos está a 1, ya que su código es $76)
/INT se activa una vez ejecutados los 32 NOPs correspondientes a una línea de pantalla. Esto es así porque el registro R se incrementa cada vez que se ejecuta una instrucción, y este se carga adecuadamente, antes de hacer el salto a la zona de pantalla, con un valor tal que, después incrementarse 33 veces su bit 6 se hace 0.
El contenido del registro R, que es el encargado de direccionar el refresco de la memoria, va a parar al bus de direcciones al final del ciclo “fetch” o de búsqueda de instrucciones, por lo que A6=0 y se activa /INT, interrumpiendo la pausa en la que se encontraba el procesador (con HALT) y continuando con la ejecución del programa.
Generador del sincronismo vertical/Decodificación de entrada/salida
En el ZX80, el sincronismo vertical se genera aprovechando la lectura del teclado. Es decir el programa de la ROM del ZX80 se las ingenia para hacer una lectura de teclado cada vez que toca generar un sincronismo vertical, por lo que el hardware aprovecha la misma lógica para dicha lectura y para la generación de VSYNC.
El siguiente circuito es el encargado de detectar una lectura de teclado.
Cuando realizamos una lectura de teclado (puerto $FEFE) comprobamos únicamente que A0=0, lo que implica que interpretaremos como tal cualquier lectura de un puerto par.
Mediante las dos puertas OR de IC17 de la derecha del circuito comprobamos que /RD=0, /IORQ = 0 y A0=0 dando como resultado la señal /KBD.
Si tenemos una escritura de puerto la salida 8 de IC11 estará a 1 por loa que el clear del tercer biestable estará a 1, como el preset está a 1 el biestable dejará pasar el dato y como no es posible una lectura y una escritura de manera simultánea tendremos a 0 la salida 11 de IC11.
Por otro lado, si tenemos una lectura de puerto la salida 11 de IC11 sera 1 por lo que se reseteará el contador de scanlines. Adicionalmente la salida 8 de IC cambiará a 0 lo que hará un reset en el último flip-flop de la derecha generando el pulso de VSYNC.
En cualquier otro momento en el que no estemos realizando una lectura o una escritura se mantendrá el estado anterior.
La exactitud del momento en que salta este sincronismo depende exclusivamente de lanzar la lectura del teclado en el momento correcto, por lo que para ser capaz de ajustar el programa de la ROM debe perder algo de tiempo en el último momento.
Código: Seleccionar todo
;; KEYBOARD
L013F: LD B,$08 ; (7) set counter to 8
;; KB-1
L0141: DJNZ L0141 ; (13,8) and loop back 7 times. (7*13+8)
; "WASTE 99 T-STATES"
;; KB-2
L0143: LD HL,($401E) ; (16) fetch two-byte FRAMES value.
INC HL ; ( 6) increment
LD ($401E),HL ; (16) and store in FRAMES again.
; now read the keyboard
LD HL,$FFFF ; (10) prepare a buffer
LD B,$FE ; ( 7) set B to $FE
LD C,B ; ( 4) now BC is $FEFE - slightly slower than
; the equally time-critical LD BC,$FEFE (10)
; that is used in the ZX81 ROM.
IN A,(C) ; (12) now read port $FEFE the half-row with
; the shift key.
; "START FRAME SYNC"
Es decir, no se genera la señal de blackporch, por lo que la imagen aparece completamente negra en las teles modernas.
La placa incorpora dos soluciones a este problema, seleccionables mediante jumpers:
- Solución propuesta por jose_leandro, añadiendo un LM. http://trastero.speccy.org/cosas/JL/zx8 ... video.html
- Solución propuesta por Grant Searle en su página sobre el zx80, basada en unas pocas puertas lógica.
La solución de jose_leandro se ve mejor pero es necesario ajustarla mediante un par de resistencias variables.
Etiquetas para la caja:
Teclados (imagen sacada de la web de Grant Searle)
Logo (imagen modificada de la web de Grant Searle)
Rayas
Funciones
Lista de interesados de la primera tirada de 10 unidades.
1- wilco2009 - Placa + componentes, Pagado.
2- flopping - Placa.
3- Dandare - Placa, Pagado
4- BCH - Placa + componentes, Pagado
5- evas2 - Placa, Pagado
6- overCLK* - Placa + componentes, Pagado - > Habi
7- shikitin - Placa + componentes, Pagado -> carmeloco
8- vidamia* - Placa + componentes, Pagado -> jose_leandro
9- Sinclair200 (M) - Placa + componentes, Pagado ->
10- Mikes - Placa + componentes.