La unión de Arduino y el procesador clásico.


Las retrocomputadoras vienen en diversos grados de meticulosidad. Algunos están contentos con la emulación. Otros prefieren FPGA, porque resulta que no es emulación, sino recreación. Finalmente, sirva el tercer procesador.

¡Pero el procesador necesita mucho para funcionar! Nuevamente, el dilema: ¿tomar chips reales de los mismos años, o poner todo en el FPGA, dejando el procesador afuera? Sin embargo, ¿por qué es necesario FPGA? ¡Viva la unión del Arduino y el procesador clásico!

Dale a tu Arduino un "segundo cerebro" y hazlo más inteligente.

Un verdadero microprocesador de ocho bits ejecuta programas, mientras que un Arduino emula ROM, RAM y periféricos simples.

Diseñe periféricos virtuales en Arduino IDE y ejecute el código del ensamblador en el microprocesador. No es necesario ensamblar circuitos complejos y flashear ROM paralelas.

Microprocesadores compatibles: 6502, 6809 y Z80 (18581), otros están en camino.

Una pantalla con un microprocesador no interfiere con la conexión de otras pantallas: con pantallas LCD, tarjetas de memoria, etc.

Además del lenguaje de autoensamblaje, puede intentar ejecutar algún código clásico en el microprocesador.

Es cierto que el microprocesador funcionará a una frecuencia muy baja, aproximadamente 95 kHz, su valor exacto depende de la optimización del código de emulación periférica.

La distribución del espacio de direcciones se establece mediante programación en un boceto. El microprocesador se puede asignar de 4 a 6 kB de 8 kB de RAM disponible en el Arduino Mega. ROM puede asignar más de 200 kB de los 256 disponibles.

El puerto serie Arduino Mega puede emular UART.

Los circuitos, los dibujos de la placa, los archivos Gerber están disponibles en CC-BY-SA 4.0 aquí . Al mismo tiempo, hay un requisito para adjuntar el archivo README.md, porque contiene la siguiente advertencia:
¡No conecte el escudo hasta que se cargue el boceto de emulación periférica! De lo contrario, es posible acortar las líneas de salida del microprocesador.
Sí, y en el boceto en sí, algo debe rehacerse cuidadosamente por la misma razón.

El esquema del dispositivo en 6502:



El esquema del dispositivo en 6809:



Esquema del dispositivo en el Z80:



Ya puedes ejecutar:

En un dispositivo con 6502 - Apple I, Woz Monitor + ROM con BASIC

En un dispositivo con 6809: un análogo de una computadora hecha en casa Simon6809 del mismo desarrollador, un monitor de entrenamiento con ensamblador y desensamblador

En un dispositivo con Z80, hasta ahora solo una prueba de eco del puerto serie , lo que le permite verificar el rendimiento del 8251 virtual (KR580VV51A).

Firmware para emular periféricos: bajo la licencia MIT.

Breves descripciones del principio de acción:

Al dispositivo 6502

Al dispositivo en 6809

Al dispositivo en el Z80 - en preparación.

El desarrollador está tratando de vender dispositivos, pero con entrega solo en los Estados Unidos. No hay una razón particular para comprar, ya que el esquema es muy simple, puede repetirlo en un pedazo de la placa en una hora.

Se planea desarrollar tableros similares en RCA1802, 68008, 8085 (182185), 8088 (181088). Acerca de K1801BM1 no se dice, pero puede arrojar esa idea al autor.

Archivos:

Al dispositivo en 6502: instrucciones de montaje , serigrafía , diagrama

Al dispositivo en 6809: instrucciones de montaje , serigrafía , diagrama

Al dispositivo en Z80: instrucciones de montaje , serigrafía , diagrama

Considere la interacción del Arduino y el dispositivo 6502. El Arduino cambia periódicamente el nivel en la entrada del microprocesador, diseñado para suministrar pulsos de reloj, de cero a uno y viceversa. En cada ciclo, verifica lo que sucede en las líneas de control y el bus de direcciones y, según la situación, lee la información del bus de datos o la envía allí. Arduino también puede controlar las líneas IRQ y NMI, causando interrupciones. La figura muestra los tipos de datos y las direcciones de su transmisión:



La correspondencia de los puertos Arduino y las salidas del microprocesador se configura en el boceto:

/* Digital Pin Assignments */ #define DATA_OUT PORTL #define DATA_IN PINL #define ADDR_H PINC #define ADDR_L PINA #define ADDR ((unsigned int) (ADDR_H << 8 | ADDR_L)) #define uP_RESET_N 38 #define uP_RW_N 40 #define uP_RDY 39 #define uP_SO_N 41 #define uP_IRQ_N 50 #define uP_NMI_N 51 #define uP_E 52 #define uP_GPIO 53 

Dividiremos cada medida en los siguientes eventos:

CLK cambia el estado de uno a cero (disminución)
CLK está en un estado de cero
CLK cambia el estado de uno a cero (aumento)
CLK está en estado unitario
CLK vuelve a cambiar el estado de uno a cero ...

¿Qué sucede durante los momentos de transición estatal?

6502 recibe pulsos de reloj en la entrada CLK0, los almacena en el búfer y los envía a dos salidas: CLK1 y CLK2. Aunque todos los eventos en el microprocesador están vinculados a CLK1, suponemos que el retraso es pequeño y están vinculados a CLK0, la línea a lo largo de la cual el microprocesador recibe pulsos de reloj de Arduino. Y llame a la señal solo CLK.



1. CLK cambia el estado de uno a cero.

2. El microprocesador envía una nueva dirección al bus de direcciones y una señal de conmutación entre lectura y escritura en la salida R / W. Pero aún no está listo para el intercambio de datos.

3. CLK entra en estado de unidad, y esto significa que el intercambio de datos ha comenzado. Si se trata de una operación de lectura, el microprocesador transfiere las salidas del bus de datos al estado de entrada y recibe datos, y si la operación de escritura, los transfiere al estado de salida y envía datos. Y la señal R / W cambia el dispositivo externo al modo de escritura o lectura, lo contrario del estado correspondiente del microprocesador.

4. CLK va a cero. Ahora, ni el microprocesador ni los dispositivos de entrada-salida envían nada al bus de datos. El microprocesador puede configurar la línea del bus de datos y el pin R / W a un nuevo estado.

Una explicación simple, comprensible para el niño. Quien nunca piensa en estas "intrigas detrás de escena", si solo programara microcontroladores. Incluso en ensamblador.

Si necesita conectar su dispositivo periférico, debe tener tiempo para preparar los datos antes de que la unidad (tiempo de preparación) aparezca en la línea CLK, y mientras la unidad esté allí, no la cambie. Si el dispositivo periférico no tiene tiempo para preparar los datos mientras CLK es cero, o lo cambia cuando la unidad está allí, se preguntará durante mucho tiempo por qué su código no funciona. Dado que la frecuencia de reloj del microprocesador es de diez a quince veces menor que la frecuencia nominal, es fácil cumplir con este requisito. Pero es necesario.

Por lo tanto, debe "enseñar" a Arduino para generar pulsos de reloj, verificar continuamente lo que sucede en la dirección y las líneas R / W e interactuar con el bus de datos en consecuencia. Para hacer esto, el boceto utiliza la interrupción del temporizador timer1, que genera pulsos con una frecuencia de 95 kHz. Arduino funciona mucho más rápido que el microprocesador y, por lo tanto, entre sus relojes, logra leer y preparar todo. Es importante asegurarse de que después de modificar el boceto, esta condición continúe cumpliéndose.

Aquí hay un extracto del boceto, que muestra cómo el CLK va de cero a uno, y qué sucede a continuación:

 //////////////////////////////////////////////////////////////////// // Processor Control Loop //////////////////////////////////////////////////////////////////// // This is where the action is. // it reads processor control signals and acts accordingly. // ISR(TIMER1_COMPA_vect) { // Drive CLK high CLK_E_HIGH; // Let's capture the ADDR bus uP_ADDR = ADDR; if (STATE_RW_N) ////////////////////////////////////////////////////////////////// // HIGH = READ transaction { // uP wants to read so Arduino to drive databus to uP: DATA_DIR = DIR_OUT; // Check what device uP_ADDR corresponds to: // ROM? if ( (ROM_START <= uP_ADDR) && (uP_ADDR <= ROM_END) ) DATA_OUT = pgm_read_byte_near(rom_bin + (uP_ADDR - ROM_START)); else if ( (BASIC_START <= uP_ADDR) && (uP_ADDR <= BASIC_END) ) DATA_OUT = pgm_read_byte_near(basic_bin + (uP_ADDR - BASIC_START)); else // RAM? if ( (uP_ADDR <= RAM_END) && (RAM_START <= uP_ADDR) ) DATA_OUT = RAM[uP_ADDR - RAM_START]; else // 6821? if ( KBD <=uP_ADDR && uP_ADDR <= DSPCR ) { // KBD? if (uP_ADDR == KBD) { ... // handle KBD register } else // KBDCR? if (uP_ADDR == KBDCR) { ... // handle KBDCR register } else // DSP? if (uP_ADDR == DSP) { ... // handle DSP register } else // DSPCR? if (uP_ADDR == DSPCR) { ... // handle DSPCR register } } } else ////////////////////////////////////////////////////////////////// // R/W = LOW = WRITE { // RAM? if ( (uP_ADDR <= RAM_END) && (RAM_START <= uP_ADDR) ) RAM[uP_ADDR - RAM_START] = DATA_IN; else // 6821? if ( KBD <=uP_ADDR && uP_ADDR <= DSPCR ) { // KBD? if (uP_ADDR == KBD) { ... // handle KBD register } else // KBDCR? if (uP_ADDR == KBDCR) { ... // handle KBDCR register } else // DSP? if (uP_ADDR == DSP) { ... // handle DSP register } else // DSPCR? if (uP_ADDR == DSPCR) { ... // handle DSPCR register } } } //////////////////////////////////////////////////////////////// // We are done with this cycle. // one full cycle complete clock_cycle_count ++; // start next cycle CLK_E_LOW; // If Arduino was driving the bus, no need anymore. // natural delay for DATA Hold time after CLK goes low (t_HR) DATA_DIR = DIR_IN; } 

La asignación del espacio de direcciones se puede hacer de cualquier manera, en un boceto no modificado es lo mismo que en Apple 1 con 256 bytes de ROM, 8 kilobytes de ROM para BASIC, 4 kilobytes de RAM y 6821 dispositivo de entrada-salida.

 // MEMORY LAYOUT // 4K MEMORY #define RAM_START 0x0000 #define RAM_END 0x0FFF byte RAM[RAM_END-RAM_START+1]; // ROMs (Monitor + Basic) #define ROM_START 0xFF00 #define ROM_END 0xFFFF #define BASIC_START 0xE000 #define BASIC_END 0xEFFF //////////////////////////////////////////////////////////////////// // Woz Monitor Code //////////////////////////////////////////////////////////////////// // PROGMEM const unsigned char rom_bin[] = { 0xd8, 0x58, 0xa0, 0x7f, 0x8c, 0x12, 0xd0, 0xa9, 0xa7, 0x8d, 0x11, 0xd0, ... 0x00, 0xff, 0x00, 0x00 }; // BASIC ROM starts at E000 PROGMEM const unsigned char basic_bin[] = { 0x4C, 0xB0, 0xE2, 0xAD, 0x11, 0xD0, 0x10, 0xFB, ... 0xE0, 0x80, 0xD0, 0x01, 0x88, 0x4C, 0x0C, 0xE0 }; 

RAM es emulada por la matriz de bytes RAM [RAM_END-RAM_START + 1]. Se necesitan dos palabras clave PROGMEM para que el contenido de las ROM emuladas se almacene en la memoria flash del microcontrolador.

El 6821 está emulado lo suficiente para que el teclado virtual y la pantalla funcionen a través del "terminal". Monitor Woz y trabajo BASIC, que es lo que buscaba el autor.

Para emular cualquier dispositivo periférico, debe leer cuidadosamente su hoja de datos y averiguar qué registros tiene y para qué sirven. La conveniencia de la emulación radica en la flexibilidad con la que puede hacer análogos de software de la periferia.

Los dispositivos de E / S se encuentran en el espacio de direcciones del microprocesador; se accede a ellos de la misma manera que las celdas de memoria. Para utilizar los periféricos de "hierro", como una pantalla LCD, una tarjeta de memoria, salida de sonido, debe asignar un lugar en el espacio de direcciones.

Referencias

www.6502.org
www.callapple.org/soft/ap1/emul.html
skilldrick.imtqy.com/easy6502
searle.hostei.com/grant/6502/Simple6502.html
wilsonminesco.com/6502primer
SB-Assembler: www.sbprojects.net/sbasm

Vaya a 6809, contiene:

Dos baterías de ocho bits A y B, que se pueden combinar en una batería de seis bits
Dos índices de pila de 16 bits
Direccionamiento relativo al contador de instrucciones
Sumar o restar automáticamente 1 o 2
Multiplicación de dos números sin signo de ocho dígitos
Aritmética de 16 bits
Transferencia e intercambio de datos entre todos los registros.
Escribir y leer todos los registros y cualquier combinación de ellos.

El microprocesador 6809E (externo) necesita un reloj externo, mientras que el 6809 tiene uno interno. En Hitachi, se les llama, respectivamente, 6309E y 6309, difieren de las habituales en que operan en forma de 32 bits dentro de la operación, pero es posible cambiar al modo de compatibilidad con la versión clásica.

En realidad, todo el proyecto RetroShield comenzó porque el autor quería actualizar su computadora casera Simon6809 y nombrar el resultado Simon6809 Turbo. Pero resultó que los chips lógicos estándar para todo lo que quería implementar allí requerirían mucho. Por lo tanto, el autor formuló la idea de RetroShield por primera vez en relación con 6809, y solo entonces pensó: "¿y si lo mismo con otros procesadores hacen lo mismo?".

El dispositivo, por supuesto, utiliza el 6809E, que requiere un reloj externo, para que pueda sincronizar su trabajo desde el exterior. Las líneas E y Q para ambos procesadores tienen el mismo nombre, solo 6809 tienen salidas y 6809E tienen entradas.

Arduino interactúa con 6809 de la misma manera que con 6502, pero tiene dos entradas de reloj: E y Q, y tres entradas de interrupción: IRQ, FIRQ y NMI.



Esta vez, la correspondencia entre los puertos Arduino y los pines del microprocesador se configura de la siguiente manera:

 /* Digital Pin Assignments */ #define DATA_OUT PORTL #define DATA_IN PINL #define ADDR_H PINC #define ADDR_L PINA #define ADDR ((unsigned int) (ADDR_H << 8 | ADDR_L)) #define uP_RESET_N 38 #define uP_E 52 #define uP_Q 53 #define uP_RW_N 40 #define uP_FIRQ_N 41 #define uP_IRQ_N 50 #define uP_NMI_N 51 #define uP_GPIO 39 

Como se puede ver en los gráficos, la señal Q se desplaza en relación con E en un cuarto del período:

Apenas prestaremos atención a Q, ya que todos los eventos están vinculados a E. Y todo sucede así:



  1. E cambia a cero. El procesador establece una nueva dirección en el bus de direcciones y cambia el estado de la línea R / W.
  2. E cambia a uno, el procesador se prepara para el intercambio de datos.
  3. No importa lo que le pase al bus de datos siempre que E sea uno, lo principal es que los datos requeridos están presentes allí en el momento en que E vuelve a cero.
  4. Al leer datos, el dispositivo de E / S debe suministrar los datos requeridos al bus de datos antes de que la línea E pase de uno a cero (el número 17 en el círculo muestra el retraso mínimo).
  5. Al grabar, el dispositivo de E / S debe corregir los datos en algún registro en la forma en que estaban en el momento en que E pasó de uno a cero. El procesador proporcionará estos datos en el bus incluso antes, en el momento de la transición de Q a uno (el número 20 en el círculo).
  6. Después de la transición de E a cero, todo se repite.

Todo lo dicho anteriormente sobre 6502 sobre la necesidad de un dispositivo periférico (incluido uno virtual) para desarrollar todas las señales a tiempo se refiere a 6809.

Generación de las señales E y Q, como en el caso de 6502, con la única diferencia de que hay dos señales, y deben cambiarse de acuerdo con los gráficos. Y así, una subrutina llamada a la interrupción realiza la entrada o salida de datos en los momentos requeridos.

El espacio de direcciones en el boceto no modificado se distribuye de la misma manera que en la computadora Simon6809 casera :

 // MEMORY #define RAM_START 0x0000 #define RAM_END 0x0FFF #define ROM_START 0xE000 #define ROM_END 0xFFFF byte RAM[RAM_END-RAM_START+1]; //////////////////////////////////////////////////////////////////// // Monitor Code //////////////////////////////////////////////////////////////////// // static const unsigned char PROGMEM const unsigned char simon09_bin[] = { 0x1a, 0xff, 0x4f, 0x1f, 0x8b, 0x0f, 0x36, 0x7f, 0x01, 0xa5, 0x10, 0xce, ... 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0f, 0xe0, 0x00 }; 

La RAM y la ROM se almacenan en matrices de la misma manera que en la variante 6502, con la única diferencia de que solo hay una matriz con datos de ROM.

A los dispositivos de E / S también se les asignan porciones del espacio de direcciones, y pueden ser virtuales o reales. Como Simon6809 es una máquina moderna basada en una base elemental vintage, intercambia datos a través de FTDI desde la PC en la que se ejecuta el "terminal". Aquí se emula.

Referencias

Mucha información sobre 6809 en la página de Arto
Artículo de Wikipedia sobre 6809
Sistemas SWTPc 6809
Artículo de Wikipedia sobre el sistema operativo FLEX

Source: https://habr.com/ru/post/446048/


All Articles