Arquitectura y programación Fairchild Channel F

"Homebrew Channel F sería como programar sprites a través de puentes de hardware ..."
/ chadtower, foro de atariage /



La consola de juegos Fairchild Channel F , también conocida como VES, apareció en noviembre de 1976. A diferencia de sus predecesores, como Ping-Pong, Tenis (en la misma fila, el "Video Sports" soviético), tenía una diferencia muy significativa: la presencia de un microprocesador y cartuchos con programas. Antes de esto, los juegos en consolas se implementaban con una lógica estricta: el programa, en el sentido moderno, estaba ausente allí.

Fairchild Channel F fue lanzado hasta 1983. Durante este tiempo, se vendieron más de un cuarto de millón de estas consolas y se lanzaron entre 30 y 40 juegos , algunos de los cuales ya estaban en la década de 2000.

Hablando de la superioridad en términos de uso de un microprocesador, vale la pena señalar que RCA Studio II, del que hablé en un artículo anterior, solo se retrasó un par de meses, pero resultó ser significativamente más débil que el Canal F, por lo que falló en las ventas. Sin embargo, la aparición, menos de un año después, Atari VCS - y reemplazó al Canal F. del mercado.

El desarrollo de Fairchild_Channel_F, como tal, no fue así. En el Sistema II y varios clones, como Saba Videoplay 2 (1979), las diferencias fueron principalmente en el cuerpo, los joysticks (por cierto, todos entendieron, excepto las posiciones habituales, la rotación de la perilla) y la cantidad de fichas. Arquitectónicamente, todo era casi idéntico.

¿Qué es el canal F?

CPU


El procesador, en las tradiciones de la época, fue producido por la misma compañía Fairchild que la consola misma y se llama F8 en.wikipedia.org/wiki/Fairchild_F8 . Este es un procesador de 8 bits de 1974, que funciona a una frecuencia de 1.8 MHz (una instrucción toma de 1 a 6 ciclos de reloj).



Sin embargo, puede llamarse un microprocesador solo con un estiramiento, ya que este procesador consta de dos chips: un dispositivo informático 3850CPU que contiene ALU, una batería, 64 bytes de SRAM, la lógica necesaria para ejecutar instrucciones, dos puertos (¡no hay bus de direcciones!) Y 3851PSU (programable Unidad de almacenamiento), que contiene 1kb de ROM (utilizada para BIOS), un puntero de instrucciones, esquemas de direccionamiento de memoria, interrupciones, un temporizador (las interrupciones y un temporizador no se usan específicamente en el Canal F).

Más tarde, apareció el chip F3859, que combinaba la CPU y la fuente de alimentación en el mismo chip y Mostek 3870, una versión ligeramente mejorada, lanzada hasta la década de 1990. Sin embargo, esta es otra historia. Curiosamente, a veces el F8 se llama microcontrolador (en particular, debido a la presencia de un temporizador y puertos) y se lo conoce como el antepasado de la familia Intel MCS-48 (8048).

Además del canal F, el procesador F8 también se usó en la computadora VideoBrain y en la computadora de ajedrez CompuChess . En general, es sorprendente que haya muy poca información sobre este procesador. Con la excepción de un par de descripciones de Fairchild y el código fuente de varios juegos y ejemplos específicamente para el Canal F, no hay nada más. Parece que este procesador no se ha utilizado en ningún otro lugar, lo que parece increíble (dado que sus versiones avanzadas se han lanzado durante bastante tiempo). Asumiré que todos los demás dispositivos donde se utilizó fueron para fines militares.

Ahora un poco sobre las características del procesador. Reflexione sobre el conjunto y las funciones de sus registros. Creo que esta es una de las arquitecturas más confusas que existían en ese momento (las modernas probablemente pueden extenderse, pero la comparación será incorrecta, porque están diseñadas para compiladores. Las personas vivas trabajaron con F8).

Hay muchos registros en el procesador. Además de la batería A de 8 bits y el registro de bandera W (I, O, Z, C, S), también hay un "bloc de notas": 64 celdas de ocho bits con varias funciones.

Las primeras nueve celdas se usan como registros de propósito general R0-R8 en comandos como 'lr a, 7 "(cargue el contenido del registro R7 en la batería). Tenga en cuenta que la letra R no está indicada, solo se escribe el número de registro. Qué se entiende exactamente, el número o el número debe estar claro por el contexto. Digamos, en el caso de la instrucción lr, simplemente no puede haber números. Y si, por ejemplo, "li 7" (carga una constante en la batería), entonces es exactamente un número, no un registro.

Las celdas 9, 10-11 (H), 12-13 (K), 14-15 (Q) están diseñadas para guardar otros registros en diferentes situaciones, como llamar a subprogramas.

Los registros R16-R63 son accesibles solo a través de un registro de índice ISAR especial (Registro indirecto de direcciones de bloc de notas), como seis memorias intermedias de ocho bytes que se forman a partir de las celdas 16-23, 24-31, 32-39, 40-47, 48-55, 56-63 .

El ISAR de seis bits se divide en dos partes de 3 bits. Al aumentar o disminuir ISAR en uno, solo se ven afectados los 3 bits inferiores, es decir el direccionamiento se lleva a cabo dentro de uno de los seis búferes de ocho bytes mencionados (al mismo tiempo, el final del búfer se puede rastrear mediante las instrucciones de ramificación condicionales br7 especiales).

clr ; 0 -> A ; set ISAR to full address Ox27 (octal 27) lisu 2 ; buffer N2 lisl 7 ; index within buffer N2 loop: lr d,a ; A-> buffer N2[index], than decrement ISAR (27, 26, 25, ... ) br7 loop ; go further if low part of ISAR contains 7 (end of buffer N2). if not, go loop again 

En este caso, "d" en la instrucción "lr d, a" no es el nombre del registro, sino una señal de que el ISAR deberá reducirse ("i" - aumentar, "s" - dejar sin cambios).

Hay otra forma de direccionamiento indirecto: a través del registro DC0 (Contador de datos):

  dci data_addr ; data_addr -> DC0 lm ; [data_addr] -> A, DC0 + 1 -> DC0 ... data_addr: db 0,1,2,3,... 

Si necesita transferir datos de un área de memoria a otra, se usa adicionalmente el comando xdc, que intercambia el contenido de los registros DC0 y DC1. Es decir leemos de la dirección señalada por DC0, luego hacemos xdc y escribimos en la dirección a la que ahora apunta DC1. Entonces otra vez xdc, etc. Es decir DC1 es un tipo de registro de sombra para almacenar una copia de DC0. Es imposible acceder directamente a él (excepto el comando xdc).

Los ejemplos anteriores ilustran solo una parte de las posibilidades en términos de direccionamiento, de hecho, hay más de ellas.

También en F8 hay cuatro puertos: 0,1,4,5, en los que puede escribir con el comando out y leer con el comando in. En el canal F, los puertos se utilizan para generar gráficos, sonido y leer el estado del joystick.

No me detendré en otras instrucciones como aritmética, transiciones, etc., son bastante estándar. Solo noto que la elección de los registros sobre los que puede realizar acciones es muy limitada, por lo que el código crece rápidamente debido a la necesidad de mover constantemente los valores de un lado a otro.

No hay resta (solo hay suma). Las instrucciones de decremento (ds) e incremento (inc) por unidad son asimétricas. ds solo funciona con los registros r0-r8, inc, solo con la batería.

El salto incondicional estropea la batería.

Un ejemplo de un ciclo regular:

  li 25 ; (r4) number of iterations lr 4,a next: ds 4 ; r4-- bnz next ; until r4 == 0 

Rutinas


Dado que F8 no tiene una pila de hardware, existen dificultades con las llamadas de subprograma anidadas. Una llamada y devolución normales se ve así:

  ; ...code pi sub ; Pushes address of next instruction to PC1 ; address of sub is stored in PC0 (jump to subroutine) ; ...code continues sub: ; ... often used code pop ; Move return address from PC1 to PC0 

Aquí PC0 es un puntero de instrucción regular. PC1: el llamado "registro de pila". No tiene nada que ver con la pila, solo PC0 se guarda cuando se llama a la subrutina.

Si se llama a otra subrutina desde sub, la dirección de retorno se sobrescribe y debe ser complicada (guarde la primera dirección de retorno en el registro K):

  prog: ; ...do something... pi sub1 ; Address of next instruction stored in PC1 ; sub1 is stored in PC0 (jump to subroutine) ; ...do more... sub1: lr k,p ; Copy PC1 to K, original jump address to K ; ...do something... pi sub2 ; Pushes address of next instruction to PC1 ; sub1 is stored in PC0 (jump to subroutine) ; ...do more... pk ; Store address of next instruction in PC1 ; Copy value in K to PC0 (jump back to main) sub2: ; ...do something... pop ; Move return address from PC1 to PC0 

Si también necesita un tercer nivel de anidamiento, todo se vuelve completamente triste (en el BIOS para esto hay incluso dos rutinas especiales: pushk y popk).

La recomendación general es intentar reemplazar las llamadas de subrutina con macros. Por supuesto, si no hay restricciones estrictas sobre el tamaño del código.

No hay pila de hardware en F8. Si es necesario, se implementa mediante programación, a través de ISAR y buffers.

Escribir en RAM no es muy relevante (por falta de uno), pero se ve así:

  li $FF ; set value dci $3800 ; set target address st ; write 

El recuerdo


Aunque esto suena un poco extraño, no hay RAM en Fairchild Channel F. Los dos kilobytes existentes de memoria de video (MK4027) no se muestran en el espacio de direcciones y, de hecho, no son legibles, se escriben a través de puertos. Los registros del microprocesador, incluso hasta 64, apenas se consideran correctos para la RAM.

El programa ejecutable se almacena en cartuchos ROM extraíbles, que a menudo tienen una capacidad de 2kb (algunos juegos modernos usan cartuchos de 3k, 4k y 5k). Además, hay un chip de procesador incorporado, ROM ROM de 1 KB, que contiene un juego simple como Tenis, un par de rutinas útiles e imágenes de varios personajes.

En el espacio de direcciones, el BIOS se encuentra entre $ 0000 y $ 07ff, el cartucho ROM, desde $ 0800.

Gráficos


Las capacidades gráficas del canal F son muy primitivas, ya que simplemente no hay un controlador de video en forma de un chip separado; todo se implementa en la lógica habitual, como registros de desplazamiento, compuertas y amplificadores operacionales. Es bastante inusual que diferentes fuentes mencionen diferentes resoluciones, y hay muchas opciones. El hecho es que los 2 kilobytes de memoria de video disponibles implican una resolución de 128 x 64, pero en realidad esto está lejos de ser el caso. En primer lugar, mucho depende de qué área de la imagen que se está formando en este televisor en particular sea visible (debido a que las primeras 4 columnas no se utilizan oficialmente). En segundo lugar, las últimas columnas se utilizan debajo de la paleta. En tercer lugar, parte de la memoria no se utiliza en absoluto.

Como resultado, la resolución real se puede estimar aproximadamente en 95 x 58 píxeles con 8 colores (que, sin embargo, es mucho mejor que RCA Studio II con su 64x32 en blanco y negro).

La mayoría de las consolas se lanzan en la versión NTSC, pero PAL también existe. No hay diferencias prácticas, como dicen (el número de líneas es el mismo).

Esencialmente, una plancha tan simple solo le permite dibujar puntos en la pantalla. Aunque el número total de colores mostrados es 8, sin embargo, solo se pueden mostrar cuatro dentro de una línea (puede llamar arbitrariamente a esto una paleta). La paleta se configura individualmente para cada línea, y se almacena en un lugar bastante extraño: en las columnas 125 y 126 de cada una de las líneas (que en cualquier caso están fuera del área visible). Cambiar la paleta es, respectivamente, dibujando píxeles en estas dos columnas.


(el área de memoria de video que es realmente visible en la pantalla y el área donde se establece la paleta se resaltan en amarillo)

Como se señaló anteriormente, solo hay una forma de escribir datos en VRAM: a través de los puertos. Esto indica el color, columna, fila:

X se escribe en el puerto 4, Y en el puerto 5, el color en el puerto 1, después de lo cual los datos se transfieren escribiendo una constante en el puerto 0:

  ; set color (2 bit per pixel) li $00 ; color ($00 = green, $40 = red, $80 = blue, $C0 = background) outs 1 li 104 ; X com outs 4 ; set the row li 61 ; Y com outs 5 ; transfer data to VRAM li $60 outs 0 li $50 outs 0 ; wait for update lis 6 delay: ai $ff bnz delay 

Se requiere un retraso para que todo se pueda grabar, de lo contrario, el siguiente punto no se puede dibujar. En la versión oficial, 4 todavía se agrega a la columna y la fila (se omite por simplicidad)

Llenar toda la pantalla con puntos (en un bucle) toma, por lo tanto, aproximadamente un segundo. Es importante tener en cuenta que, además de la actualización de pantalla extremadamente lenta, también existe el hecho de que no hay forma de esperar a que el haz vuelva a través del marco. En consecuencia, incluso un pequeño redibujo está inevitablemente acompañado por un parpadeo.

Ahora sobre la paleta. Estrictamente hablando, para cada línea hay dos modos: blanco y negro (cuando el fondo es negro y el primer plano es solo blanco, sin importar el píxel que se dibuje) y el color.

En el modo de color de primer plano, siempre hay tres: rojo, verde, azul (rgb). Además de uno de los tres colores de fondo: gris, azul claro, verde claro.

Para establecer la paleta en las columnas 125 y 126, escriba los siguientes valores:

 x=125 x=126 palette --------------------------------------------------------------------- 00 00 COLOR: rgb, light green bg 00 ff COLOR: rgb, light blue bg ff 00 COLOR: rgb, gray bg ff ff B/W: www, black bg 

En los juegos típicos, generalmente hacen esto: primero establecen un cierto fondo general, para el cual puede usar el procedimiento de BIOS ya preparado:
  li $c6 ; $21 - b/w palette, fill with black. $c6 - color palette, fill with gray lr 3, A pi clrscrn ; clrscrn BIOS call 

Luego, si es necesario, haga una tira con una paleta en blanco y negro (por ejemplo, para mostrar el puntaje del juego con números en blanco sobre fondo negro)


Y luego ponen píxeles en uno de los tres colores (si el fondo es gris, respectivamente - r, g, b). Como resultado, por supuesto, hay 8 colores, pero poner en un lugar específico un punto de un color arbitrario es tan fácil, es imposible. Aquí hay un conjunto de imágenes que dan una idea de los colores y sus combinaciones.

En realidad, en esto, todos los gráficos, como tales, terminan: todo lo que desea hacer se hace dibujando píxeles y manualmente. De rutinas útiles, el BIOS tiene salida de caracteres. Sin embargo, por razones de ahorro de espacio, en la ROM solo hay imágenes de números y caracteres individuales, de 5x8 píxeles de tamaño:


Sin embargo, el procedimiento para su retirada es útil y puede usarse de la siguiente manera:

  li 25 ; column lr 1,a li 25 ; row lr 2,a li %11000000 ; eg $c0 - green "0" lr 0,a ; a -> r0 pi drawchar ; call subroutine 

En la versión anterior, los dos dígitos superiores en el registro r0 determinan el color (10 - rojo, 11 - verde, 01 - azul, 00 - transparente), el resto - el número de serie del carácter (0 1 2 3 4 5 6 7 8 9 G? T SPACE MX BLOQUE: - centro || izquierda || `), comenzando desde cero. Los registros r1 y r2 se colocan, respectivamente, en una columna y una fila.

Una opción más práctica es no pensar en bits:

  li 20 ; x lr 1,a ; a -> r1 li 10 ; y lr 2,a ; a -> r2 li $40 ; char color in bits 6,7: $80 (%10000000) - red, $c0 (%11000000) - green, $40 (%01000000) - blue, $00 (%00000000) - transparent oi 1 ; index of char ( eg 3 for "3" ) lr 0,a ; combined color + char index -> r0 pi drawchar ; call subroutine 

Para tener una idea de la plataforma, escribí una introducción de 256 bytes para el pequeño concurso de introducción en Chaos Constructions'2019 . Nada especial, pero preste atención a por qué el cambio de paleta línea por línea se usa allí. Una franja horizontal progresiva, por así decirlo, resalta la línea que está debajo, reemplazando temporalmente todo el fondo con negro y todos los píxeles con blanco. Dado que no necesita sobrescribir los píxeles (y no necesita restaurarlos más tarde), puede hacer que esa "luz de fondo" sea muy rápida y sin parpadeos.

El segundo punto son las letras "CC". Dado que las letras "C" no están en el BIOS, la superposición de las letras GG y el número 1 entre sí se utiliza para obtener el "CC" inverso.



Sonido


El sonido es malo Oficialmente, hay tres sonidos: 120Hz, 500 Hz y 1 KHz. De hecho, obtener algo más que clics y un chirrido ahogado es problemático. Además, dicen que entre las máquinas PAL y NTSC, así como entre las versiones antiguas y nuevas, el sonido también es diferente. Sin embargo, para juegos típicos, es suficiente. Sonido encendido y apagado a través de los puertos:

  li %01000000 ; 1khz beep $40 outs 5 li %10000000 ; 500hz beep $80 outs 5 li %11000000 ; 120hz beep $c0 outs 5 ; some pause clr outs 5 ; turn off sound 

La gente incluso se divirtió tocando música. Las mejores muestras se parecen remotamente a PC-Speaker. Es cierto, de todos modos, no tiene sentido práctico: todos los recursos del procesador van a la música, no se puede hacer nada especial.

Herramientas de desarrollo


Actualmente, hay una selección ya hecha del software necesario llamado "Paquete de desarrollo".

Esto incluye ensamblador DASM, desensamblador, emulador MESS (con depurador). Todo esto funciona sin problemas al menos en Windows 7.


Parámetros para montaje y puesta en marcha:

 dasm.exe test.asm -f3 -otest.bin messd channelf -cartridge %cartPath%\test.bin -w -effect sharp -r 640x480 -ka 

El emulador es bastante bueno, aunque el depurador allí es extremadamente extraño. No pude configurar la nueva versión de MAME / MESS de inmediato (me di cuenta de que configurar MAME para una plataforma impopular que supuestamente admite es una tarea no trivial cada vez).

El emulador supone que la resolución de la región visible corresponde a minx = 5, minY = 5, maxX = 105, maxY = 61

Como no es un placer escribir algo debajo del emulador sin haber probado el resultado en vivo, tuve que resolver el problema con el emulador ROM. A petición mía, tnt23 hizo un cartucho especial (Alexander Novozhilov imprimió un estuche) en el que se inserta la EEPROM 28C16A. Debido a las peculiaridades del direccionamiento F8, todavía tuve que comprar un antiguo chip Fairchild 3853 en eBay. Como resultado, fue posible programar EEPROM para ver cómo se ve el código en una máquina en vivo.


Además, tnt23 conectó una salida de S-Video del Canal F (normalmente solo se podía conectar a un televisor a través de la entrada de antena), lo que mejoró en gran medida la calidad de la imagen y la reproducción del color.

Historia sobre Fairchild Channel F:



Recursos


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


All Articles