Tabla de contenido:

Revisando la computadora Z80: 6 pasos
Revisando la computadora Z80: 6 pasos

Video: Revisando la computadora Z80: 6 pasos

Video: Revisando la computadora Z80: 6 pasos
Video: La Computadora Vintage con un Microprocesador Z80 2024, Noviembre
Anonim
Revisando la computadora Z80
Revisando la computadora Z80
Revisando la computadora Z80
Revisando la computadora Z80

En el pasado, escribí una guía sobre cómo construir una computadora basada en Z80 y diseñé el circuito para que fuera lo más simple posible para que pudiera construirse lo más fácilmente posible. También escribí un pequeño programa usando la misma idea de simplicidad. Este diseño funcionó bastante bien, pero no estaba totalmente satisfecho con él. Comencé reescribiendo un programa que permitiera programarlo durante el tiempo de ejecución. Esto fue para permitirme probar piezas de código sin tener que dedicarlo a EEPROM, lo que a su vez me obligaría a reprogramar la EEPROM. Esto no me pareció una idea divertida. Luego comencé a pensar en los espacios de memoria. Si quisiera conectar una pieza de hardware (IO principalmente), una pieza de código podría exceder potencialmente la cantidad de espacio de memoria disponible para el sistema. Recuerde, el diseño solo usó el byte inferior del bus de direcciones y luego el bit inferior del byte alto se usó para seleccionar entre espacios ROM y RAM. Esto significaba que solo tenía 253 bytes de espacio para usar. Es posible que se pregunte por qué 253 en lugar de 256. Eso es porque mi nuevo código inyecta tres bytes de datos al final de un programa escrito (esto se tratará más adelante, ya que lo modifiqué para trabajar en el nuevo diseño).

norte

Repasé mis viejos esquemas para ver qué más estaba pasando. Encontré un pequeño defecto en el circuito de selección de memoria, que cubriré cuando llegue allí. La versión simplificada: todas las solicitudes de escritura se ejecutarían, aunque siempre se colocaron en la RAM. Probablemente esto no era algo por lo que valiera la pena preocuparse, pero quería hacerlo correctamente esta vez. Y con eso, comencé a dibujar un nuevo esquema. Las dos fotografías adjuntas a esta página son antes y después del circuito real. Limpié gran parte del cableado de espagueti, no es gracioso.

norte

Si siguió mi presentación original y planea seguir con esta, me odiará. Si está comenzando de nuevo, entonces está de suerte. Simplemente tome las partes de la lista (o su equivalente) y sígalas.

Suministros:

LM7805 - regulador de 5 voltiosZ80 - la CPU; el cerebro del sistemaAT28C64B - EEPROM. Almacenamiento de datos "permanente" utilizado para el firmware de la computadora IDT6116SA - SRAM; utilizado para almacenar código de usuario y / o almacenamiento de datos generales NE555 - Reloj del sistema 74HC374 - Octal D-Latch con / OE; utilizado como chip de entrada 74LS273 - Octal D-Latch con / MR; chip de salida TLC59211 - Chip controlador de LED (utilizado para que el 74LS273 pueda controlar LED, ya que por sí solo no es capaz de la salida de corriente) MC14572 - Este es un chip de "controlador de línea", pero lo encontré perfecto para la lógica de control de memoria. Tiene 4 inversores y una puerta NAND y NOR incorporada 74LS32 - Puerta cuádruple OR CD4001 - Puerta cuádruple NOR CD4040 - Contador de ondulación de 12 etapas; Divisor de reloj dibujado, pero no implementado (para ejecutar el sistema a velocidades de reloj más lentas) 2 resistencias de 10K Ohm: una se usa en el circuito del temporizador 555, así que use el valor que desee para ella 4 Resistencias de 1K Ohm: una se usa para el Circuito temporizador 555, así que usa lo que desees. Otro se usa para controlar los LED, así que varíelo también si lo desea. Bus de resistencias de 8x330 ohmios Bus de resistencias de 8x10K ohmios 11 LED: tres se usan para el estado del sistema y los otros ocho son salidas. Para el 8, utilicé una pantalla de gráfico de barras (HDSP-4836). 4 Condensadores: se utilizan dos en el LM7805; 0.22uF y 0.1uF. Uno es para el temporizador 555, así que use lo que crea que es correcto. El último es para reiniciar el encendido; 100uF2 N. A. Botones pulsadores: uno se utiliza para la entrada y el otro para restablecer. 8 interruptores DIP SPST: entrada de datos; Usé Piano Key styleWire. Mucho, mucho alambre

norte

NOTA: la versión de orificio pasante MC14572 es obsoleta, pero la versión SMD todavía está activa (ni siquiera en el estado "no para nuevo diseño"), por lo que es posible que deba comprar una placa de circuito para poder usarla. Se puede usar un segundo 74LS32 en lugar del MC14572 (consulte el esquema del "circuito de selección de memoria" del ible anterior)

Paso 1: descripción general rápida de cambios + esquemas

Resumen rápido de cambios + esquemas
Resumen rápido de cambios + esquemas

Cómo leer los esquemas: Una flecha apuntando hacia un chip es una entrada: Entrada> -Una flecha apuntando hacia afuera de un chip es una salida: Salida <-Los buses usan una línea en lugar de una flecha: Bus | -

norte

La mayoría de las fichas se han elaborado con sus pines exactos. El pequeño chapuzón se ha dibujado en estos chips. La mayoría de los chips también tienen números de pin y etiquetas. Pueden ser un poco difíciles de leer. Mi lápiz se estaba volviendo aburrido.

norte

En términos de conexiones de circuitos, el diseño del nuevo diseño prácticamente no ha cambiado con respecto al original. Conecté el nibble inferior del byte alto de la dirección a las memorias y luego usé el bit bajo del nibble superior (A12) para la selección de RAM / ROM. Esto significó que el espacio de la ROM pasó de 0000-00FF a 0000-0FFF. El espacio de RAM pasó de 0100-01FF a 1000-1FFF. También cambié la lógica de control de memoria por un mejor diseño y agregué dos nuevos LED de estado (y algo de lógica de pegamento). También dibujé (pero no cableé) un circuito divisor de reloj. Debía realizar dos funciones. La función obvia es dividir la frecuencia del reloj hacia abajo. La otra función es para propósitos de PWM (Modulación de ancho de pulso), ya que el 555 no genera ondas con ciclos de trabajo del 50%. Eso realmente no importa en este circuito, pero si quisiera usar el reloj para controlar algunos LED, definitivamente notará los efectos (uno (conjunto de) LED (s) será más tenue que el otro). El resto de la circuitería se mantiene esencialmente sin cambios.

Paso 2: CPU, memoria y control de la memoria

Control de CPU, memoria y memoria
Control de CPU, memoria y memoria
Control de CPU, memoria y memoria
Control de CPU, memoria y memoria
Control de CPU, memoria y memoria
Control de CPU, memoria y memoria
Control de CPU, memoria y memoria
Control de CPU, memoria y memoria

Esta es la parte en la que los lectores de mi versión anterior me odian. En la construcción original, simplemente arrojé piezas en el tablero en un lugar en el que parecía que impondrían un pequeño problema para conectarse. El resultado parecía como si alguien hubiera tirado un plato de espaguetis encima y era como "¡alambres!" Quería limpiarlo un poco, así que comencé rompiendo todo excepto la CPU, la RAM y la ROM. Arranqué casi todo el circuito de entrada, el circuito de salida y la lógica del pegamento. Casi me duele hacerlo, pero era necesario. Dejé todas las conexiones de datos intactas y el byte inferior del bus de direcciones. Luego conecté los siguientes cuatro bits del bus de direcciones (A8-A11) al chip ROM. Esta vez tuve cuidado de rodear el chip para que fuera más fácil levantarlo para reprogramarlo. También salté las conexiones de dirección al chip RAM.

norte

Con eso fuera del camino, ahora tenía que conectar la lógica de control de memoria. En el esquema original, había conectado la línea / MREQ del procesador directamente a / CE a ambos chips de memoria, luego conecté / WR a la RAM / WE. Luego tuve la CPU / RD y / MREQ lógicamente OR juntos, así como A9. Básicamente, se configuró para que todas las solicitudes de memoria activaran tanto la RAM como la ROM, pero se usó A9 para seleccionar cuál de los chips '/ OE se seleccionó. Esto estuvo bien y todo porque los chips permanecerían inactivos hasta que se realizara una solicitud de memoria y luego solo uno / OE estaría activo durante una solicitud de lectura. Esto evitó la diafonía, pero introdujo un matiz incómodo. Debido a que A9 solo se usó para determinar qué chip estaba emitiendo datos y debido a que la CPU tenía acceso directo al pin de la RAM / WE, todas y cada una de las solicitudes de escritura pasarían. Esto estuvo bien para la ROM porque su modo de escritura se inhibe atando / WE directamente al suministro de 5V. Sin embargo, la RAM se escribiría independientemente de A9. Esto significaba que un intento de escritura en una ubicación de espacio ROM escribiría en la misma ubicación en el espacio RAM.

norte

Una solución para esto sería volver a cablear la lógica de control para que la CPU tenga acceso directo a los pines / OE y / WE de los chips y luego usar MREQ y A12 para seleccionar qué chips / CE se activaron. Seguí esta idea, pero en lugar de usar cuatro puertas NOR y un inversor como el diseño original, encontré un pequeño chip incómodo que era perfecto para la tarea. Tuve que crear un circuito que usara solo las puertas lógicas disponibles en el chip, pero eso fue bastante fácil. A12 alimenta directamente a una puerta NAND y una puerta NOR. / MREQ se alimenta a la puerta NOR y su complemento se alimenta a la puerta NAND. La puerta NAND se usa para controlar / CE para la RAM y la salida NOR se invierte y se usa para controlar la ROM / CE. Esto hace que / MREQ tenga que ser bajo antes de seleccionar cualquiera de los chips y luego A12 elige cuál se selecciona. Con esta configuración, ahora cualquier solicitud de escritura en ROM no hará nada. También ahorra energía porque solo un chip está activo en lugar de ambos. En cuanto al chip lógico en sí, todavía tenemos dos inversores sin usar en su interior. Uno se acostumbrará más tarde, pero llegaremos allí cuando lleguemos.

Paso 3: LED de estado del sistema

LED de estado del sistema
LED de estado del sistema
LED de estado del sistema
LED de estado del sistema

Antes de comenzar este proyecto, estaba tratando de interactuar con un CI determinado, pero tenía problemas con él. Inseguro de lo que estaba pasando, utilicé un LED de montaje en panel para sondear (uno de esos conjuntos que tiene una resistencia incorporada). Hacer esto me dio una idea de nostalgia que todavía se usa hoy: LED de estado que se usan para indicar si se estaba leyendo o escribiendo en la memoria. Se iba a utilizar junto con el LED de entrada que ya tenía. El LED de entrada se conectó al generador de señal / WAIT para indicarnos que el sistema está, bueno, esperando la entrada (llegaré allí, no te preocupes). Consideré agregar un LED para indicar una escritura IO, pero pensé que el cambio de los LED de salida ya sería un gran indicador de eso. Pensando en ello, todavía puedo agregarlo. No obstante, encuentro útil saber si la memoria se está leyendo o escribiendo. Bueno, es útil para la depuración de programas, de todos modos. De hecho, lo utilicé mucho como tal cuando intenté que mi programa funcionara: “¿Por qué está escribiendo en la memoria? ¡No se supone que esté haciendo eso todavía!"

norte

Para controlar estos LED, utilicé la puerta NOR cuádruple. Usé todas las puertas. Solo se utilizaron dos para generar las señales de estado, pero el chip no tiene la capacidad de potencia para impulsar realmente los LED. Son capaces de consumir tanta energía, así que utilicé las otras dos puertas NOR como inversores y conecté los LED como tales. Debido a que un LED se usa para indicar lecturas y el otro para escrituras, y no se producirá una solicitud de lectura y escritura al mismo tiempo, pude salirse con la suya usando solo una resistencia para ambos LED. En cuanto a las señales que necesitaba decodificar, también fue bastante fácil. Quería que se indicaran todas las solicitudes de lectura de memoria, por lo que la primera puerta NOR tenía / MREQ y / RD en sus entradas. El estado de escritura fue un poco más complicado, pero igual de fácil. Todavía usé / MREQ como una entrada, pero usar / WR como la otra causaría un pequeño matiz que quería evitar. Habría indicado TODAS las solicitudes de escritura. Solo quería los que realmente pasaron. Entonces, ¿cómo haría eso? Bueno, ¿recuerdas cómo configuré el sistema para que solo se pueda escribir la RAM? Usé las RAM / CE como la otra entrada a la puerta NOR. Esto significa que el LED solo se iluminará cuando se seleccione RAM y se realice una solicitud de escritura. En cuanto al color del LED, elegí el naranja como indicador de lectura (pero solo encontré los amarillos) y el rojo como indicador de escritura.

Paso 4: entrada y salida

Entrada y salida
Entrada y salida
Entrada y salida
Entrada y salida
Entrada y salida
Entrada y salida

En el paso anterior, es posible que haya notado que ya agregué algunos de los demás componentes a la placa. Estaba reservando el espacio para no colocar accidentalmente cables donde quería un componente (por lo tanto, tendría que encontrar una nueva ubicación para dicho componente). Es posible que también haya notado que dejé los interruptores de entrada en su lugar y los conecté al riel de alimentación. Decidí que la ubicación original era el lugar perfecto y decidí colocar los LED de salida cerca (arriba). A la derecha de la barra de visualización está el pestillo de entrada. Encima está el pestillo de salida, y a la izquierda está el controlador LED. Comencé conectando la pantalla al controlador, ya que era lo más fácil de hacer. Luego conecté los interruptores al lado de entrada del pestillo de entrada. A continuación, conecté el lado de salida del pestillo de salida al controlador LED. Esto puede parecer una orden incómoda para conectarlos, pero fue por una razón. La entrada del pestillo de salida debía conectarse al bus de datos, así como la salida del pestillo de entrada. La idea era conectar las salidas del pestillo de entrada a las entradas del pestillo de salida, lo cual hice. Entonces todo lo que tenía que hacer era conectar ese lío al bus de datos. No importaba dónde iban físicamente estas conexiones porque todas estarían conectadas eléctricamente. La computadora ya casi está lista.

Paso 5: Restablecer y finalizar la entrada y salida

Lo siento, no hay fotos para este paso. Consulte el paso anterior para ver las fotografías.

norte

Es posible que haya notado en la última imagen del paso anterior, tenía un botón verde y otro chip lógico instalado. El chip es la puerta OR. Se utilizan dos puertas para generar la señal / WAIT. Bueno, uno genera la señal mediante OR-ing / IORQ y / RD desde el procesador. La salida se alimenta a la segunda puerta, donde se pone OR de nuevo a un botón pulsador. El botón eleva la entrada de la puerta, elevando así la salida. Esta salida se envía a los procesadores / pin WAIT. Mientras no está presionado, una resistencia mantiene la entrada baja. Inicialmente usé una resistencia de 10K, pero el LS32 en realidad estaba poniendo voltaje en la entrada. La resistencia no la bajó lo suficiente y tuve que reemplazarla con una 1K. De todos modos, la idea es que cuando se realiza una solicitud de lectura de E / S, la primera y la segunda puerta OR le dicen al procesador que espere. Una vez que establezca los interruptores de entrada en lo que desee, presione el botón y sacará a la CPU de la condición de espera. El LED verde de "entrada", como lo llamé en un paso anterior, está cableado de manera que cuando el pin / WAIT baja, se enciende.

norte

Pero aún no hemos terminado. El flip flop de entrada necesita una señal que le permita saber cuándo la entrada de datos es válida y debe enviarse a la CPU. Este pin de reloj está activo alto. Antes, simplemente lo conectamos al botón. Esta sigue siendo una opción válida, pero esta vez elegí ponerla en la misma salida que la segunda puerta OR. Este IC también tiene un pin / OE que debe activarse. Si se mantuviera alto, nunca insertaría datos en el bus. Si se mantiene bajo, siempre conducirá el autobús. Para solucionar esto, simplemente utilicé una tercera puerta OR. Las entradas son / IORQ y / RD y la salida va directamente al pestillo / OE.

norte

El pestillo de salida también necesita que se active el pin de reloj. Una vez más, es alto activo. En mi esquema, dibujé la cuarta puerta OR directamente conduciendo el pin usando / IORQ y / WR. Esto significaba que el pin del reloj se mantendría alto hasta que se realizara una solicitud de escritura, luego bajaría y luego volvería a subir. Esto probablemente habría estado bien porque el bus de datos todavía habría tenido datos válidos inmediatamente después del intento de escritura, pero desde un punto de vista de ingeniería, fue un diseño basura. No noté este error hasta después de haber tomado las fotos finales, pero rompí esa conexión y luego alimenté la salida de la puerta OR en uno de los inversores no utilizados de la lógica de control de memoria, luego conecté su salida al pin del reloj. También arreglé el esquema y encontré otro error que había cometido. Yo también lo corrigí.

norte

Con todo eso finalmente hecho, tenía una pequeña cantidad de trabajo por hacer: el circuito de reinicio. Agregué un botón a la placa y usé una resistencia de 10K para mantener un lado alto. El otro lado va directamente al suelo. El lado que se mantiene alto es la salida / RESET, que fue a cada chip con un pin / RESET (la CPU y el pestillo de salida). Para lograr el reinicio de encendido, agregué un capacitor a la salida / RESET. La idea es que la resistencia de gran valor haría que el condensador relativamente grande se cargue lentamente y mantenga los pines / RESET bajos durante una cierta cantidad de ciclos de reloj (la CPU necesita cuatro ciclos de reloj). Probablemente ya puedas adivinar cuál es el lado negativo de este circuito. Es el mismo negativo que la versión anterior porque es el mismo circuito. Cuando se presiona el botón, el capacitor está esencialmente en corto a través del botón. Esto es malo tanto para la tapa como para el botón, por lo que si desea que su construcción sea un poco más permanente, es posible que desee rediseñarla. Estaba pensando en otro temporizador 555 configurado en modo monoestable. Pero con eso, el circuito de la computadora ahora está terminado. Hurra. Ahora necesita programarse.

Paso 6: programación

Programar esto fue una pesadilla. Construí un programador Arduino EEPROM. No funcionó. Creé otro basado en el diseño y la codificación de otra persona. Todavía no funcionó. Volví al método probado y verdadero de configurar manualmente las direcciones y los bytes de datos a mano. De alguna manera, lo arruiné. Intenté de nuevo y todavía me equivoqué. Volví una vez más y descubrí que estaba desfasado por un solo byte, así que lo corrigí y finalmente funcionó, gracias a Dios.

norte

En cuanto al programa real, parece muy complejo y difícil de seguir, pero no lo es. De hecho, es bastante simple. La mitad está copiando números. La otra mitad se comparte entre matemáticas de 16 bits, saltos condicionales y aún más números de copia. Así que déjame repasarlo y contarte cómo funciona.

norte

La inicialización simplemente establece algunos valores de registro para que los utilice el programa. El ciclo del programa es un poco más complejo, pero no mucho. Primero, acepta la entrada al registro A en el puerto 00. Luego, el registro E se escribe en la memoria. En los dos primeros bucles, el registro E contiene datos basura, por lo que intentamos escribirlos en los dos últimos bytes del espacio ROM porque en realidad no se escribirán; A continuación, se incrementa el puntero de dirección (IY). El valor almacenado en D se mueve luego a E para escribirse a continuación. A continuación, se carga A en D y L y E se copia en H. HL es donde se realiza la comparación de valores mediante la resta y la verificación de ZF (bandera de cero). El primer valor comparado se almacena en los registros B y C. B y C se tratan como un solo registro de 16 bits, BC. Si los valores son los mismos, entonces el programa salta directamente al espacio RAM, donde se supone que reside el código de usuario. Si el código en BC no coincide, entonces HL se recarga con los valores iniciales de D y E y se compara nuevamente con el valor en SP de la misma manera que se comparó con BC. Si coincide, tiene el mismo resultado, pero se escriben tres bytes adicionales en la memoria. Los bytes son un código que hace que la CPU vuelva al principio de su programa (un reinicio del software). Sin embargo, si la segunda comparación no coincide, el programa se desplaza hasta donde obtiene un valor del usuario.

norte

LD SP, EDBFH; código exe (agrega salto)

norte

LD IY, FFEH; puntero de memoria inicial para almacenamiento de código

norte

LD BC, EDC3H; código exe (sin bucle)

norte

círculo; directiva de ensamblador para que no tengamos que saber en qué parte de la memoria reside esta parte

norte

EN A, (00H); obtener datos del programa

norte

LD (IY + 00H), E; E contiene código para ser almacenado

norte

INC IY; pasar a la siguiente ubicación de memoria

norte

LD E, D; ld D en E

norte

LD D, A; ld A en D

norte

LD H, E; ld E en H

norte

LD L, D; ld D en L

norte

O A; restablecer la bandera de acarreo

norte

SBC HL, BC; devuelve 0 si se ingresó el código exe 2

norte

JP Z, 1000H; si es así, salte y ejecute el programa

norte

LD H, E; de lo contrario, actualícelos a los valores adecuados

norte

LD L, D

norte

O A; la primera resta puede haber establecido la bandera de acarreo. Limpialo

norte

SBC HL, SP; devuelve 0 si se ingresó el código exe 1

norte

JP NZ, bucle; si no, repita el proceso (comenzando por obtener un valor)

norte

LD (IY + 00H), C3H; de lo contrario, inyecte un código de salto al final del programa de usuario

norte

LD (IY + 01H), 00H; saltar básicamente actúa como un reinicio de software

norte

LD (IY + 02H), 00H; es un reinicio completo en caso de que los registros se modifiquen

norte

JP 1000H; saltar y ejecutar el programa de usuario

Recomendado: