Arquitetura e programação RCA Studio II

"Finalmente, chegamos à instrução pela qual todos esperávamos - SEXO!"
/ do artigo sobre o microprocessador CDP1802 /




No início dos anos 1970, jogos eletrônicos simples como o Pong eram muito populares nos EUA (na URSS, seus análogos apareceram à venda em 5 a 10 anos). Como regra, esses jogos não tinham um microprocessador e memória no sentido moderno dessas palavras, mas eram construídos com lógica rígida. Consequentemente, os cartuchos substituíveis não faziam muito sentido e onde estavam - eram apenas um conjunto de jumpers que incluíam o jogo desejado.

Em 1977, dois consoles foram lançados quase simultaneamente: Fairchild Channel F e RCA Studio II . Esses foram os primeiros consoles de jogos na forma de computadores completos - com um microprocessador e programas de cartucho substituíveis.O RCA Studio II, que será discutido, não é desenvolvido apenas pela RCA , mas por uma pessoa específica - Joseph A. Weisbecker (como toda a arquitetura COSMAC) .
O primeiro desses dispositivos, o System 00 , também conhecido como COSMAC FRED (1971), foi um protótipo e não foi produzido em massa.


O processador nele foi implementado na lógica usual (no FRED2 - em dois chips chamados CDP1801 R e U, que apareceu em 1973). A RAM estava na região de 256 bytes - 4 kb, além disso, o FRED2 tinha um gravador embutido.


A primeira implementação comercial da arquitetura COSMAC foi o COSMAC ELF . Em 1976, a ELF foi posicionada como um computador para radioamadores (uma série de artigos foi publicada na revista Popular Electronics) e era uma pequena placa com interruptores, indicadores, um microprocessador CDP1802 (o mesmo 1801, mas já em um chip) e 256 bytes de RAM. Para ele, havia placas de expansão adicionais que permitiam exibir gráficos no monitor (usando o chip CDP1861), um teclado externo e um gravador foram conectados. Baseado em ELFs com extensões, ELF II e VIP apareceram. Nas ROMs COSMAC, havia uma máquina virtual chamada CHIP-8, aprimorada para jogos primitivos (comandos para gerar e mover sprites de software, gerar números aleatórios etc.). Havia outros computadores e terminais primitivos baseados nessa arquitetura.


Todos esses dispositivos eram antecessores diretos do RCA Studio II e possuem uma arquitetura de hardware e software extremamente próxima.

O RCA Studio II foi lançado em 1977 e custava US $ 150 (US $ 600 em dinheiro atual). Como costuma acontecer, o primeiro no mercado não é necessariamente o mais bem-sucedido. Em 2008, a revista PC World reconheceu esse console como o pior console de jogos de todos os tempos (o que, em princípio, não está longe da verdade): uma imagem em preto e branco dos quadrados, a ausência de joysticks (em vez deles dois campos de 10 botões) e uma dúzia de jogos - para dizer o mínimo. compradores satisfeitos.


Além disso, todos os jogos (embutidos e vendidos em cartuchos) foram escritos no pseudocódigo da máquina virtual ST2 (a mesma idéia do CHIP-8 nos COSMACs), o que tornava muito lento.

A RCA conseguiu liberar cerca de 64 mil unidades do RCA Studio II, sem contar os clones que apareceram mais tarde (Toshiba Visicom, Conic M-1200 etc.) Com o advento do Atari VCS , o desatualizado RCA Studio II e Fairchild Channel F imediatamente desistiram da luta.

CPU


Como fabricante de chips, a RCA escolheu seu próprio produto como processador de decodificador - o microprocessador RCA CDP1802 , operando a 1,78 MHz e fabricado com a tecnologia CMOS.


Seu antecessor foi o CDP1801, um processador de dois chips (totalmente compatível com 1802):


O CDP1802 é conhecido por sua versão resistente à radiação (silício em safira), na qual foi usado, por exemplo, na estação interplanetária Galileo , voando para Júpiter nos anos 90 (havia 6 desses processadores), assim como no MAGSAT .

O processador possui um esquema de uso de registro bastante complicado. Possui um acumulador D de 8 bits e dezesseis registros de 16 bits - R0..RF (R0-R15), cada um dos quais pode se tornar um ponteiro de instrução, dependendo do conteúdo do registro de 4 bits P (apontando para um de R), mutável Equipe SEP Rn. Em outras palavras - não há um único PC no processador!


Além disso, qualquer um dos R0 ... R15 pode se tornar índice (endereço). A escolha é determinada com base no valor no registro de 4 bits X (alterado pelo comando SEX Rn), após o qual o R selecionado é considerado indexado para alguns comandos.

O registro de endereço para DMA é sempre R0. Dentro da interrupção, o contador de instruções é R1.

Há um registrador de 8 bits T, usado para salvar automaticamente os registradores X e P quando ocorre uma interrupção. As interrupções são ativadas configurando o sinalizador IE Interrupt Enable via comandos RET ou DIS.

Os registradores de 4 bits I e N contêm a instrução atual executada pelo processador.

Existe um registro de bandeira - DF. Mais precisamente, um sinalizador, pois é um dígito e contém apenas um sinalizador de transporte.

Além disso, o processador possui uma porta de saída Q de bit único, cujo estado é alterado pelos comandos SEQ e REQ.

Como em muitos processadores dessa geração, a pilha no sentido usual está ausente aqui (não há comandos PUSH, POP nem o ponteiro da pilha) e, se necessário, é implementada pelas instruções existentes.

Também não há instruções tradicionais para chamar rotinas. A transição para a sub-rotina é realizada usando a instrução SEP Rn que, lembro-me, faz com que o Rn indicado registre um contador de comandos. Para retornar, a mesma instrução SEP é usada, mas com um registro que era o contador de comandos antes da chamada. Ou (em uma versão mais universal, mas mais lenta) MARK e RET são usados.

Além dos saltos condicionais e incondicionais tradicionais (a propósito - todos são absolutos), existem várias instruções SKIP que, quando a condição é atendida, pulam a próxima instrução SKIP (dois bytes). SKIP incondicional também é fornecido.

O processador 1802 é frequentemente referido como um dos primeiros processadores RISC. No entanto, no mesmo contexto, é mencionada, digamos, 6502, bem como algumas outras. É certo que a arquitetura não é muito comum e, do ponto de vista da programação, causa sentimentos confusos. Por um lado, existem até dezesseis registros de 16 bits. Por outro lado, seu conteúdo diretamente só pode ser reduzido e aumentado em um. Por exemplo, colocar uma constante em Rn é assim:

ldi $01 ; const -> D plo r6 ; D -> R6.0 ldi $02 ; const -> D phi r6 ; D -> R6.1 

Portanto, a maior parte do código está movendo bytes para frente e para trás.

Das transições por condição, existe, de fato, apenas uma transição para zero (apenas a situação em que 0 está no acumulador D) e o sinalizador de transferência são considerados. Os loops típicos são os seguintes:

 loop: ... dec r7 ; R7-- glo r7 ; R7 -> D bnz loop loop: ... adi 2 ; D = D + const xri $07 ; compare using XOR. (D == const) -> D bnz loop 

Todas as instruções aritméticas e lógicas funcionam apenas com a bateria D.

Além da porta de bit único controlada pelo SEQ / REQ, também há uma porta de quatro bits controlada pelos comandos OUT / INP. Infelizmente, não é usado no RCA Studio II.

MEMÓRIA


Existem: 2 KB de ROM (BIOS + cinco jogos embutidos) 512 bytes de RAM (metade é reservada para vídeo)
Cartão de memória

 000-2FF ROM RCA System ROM :   SP2 300-3FF ROM RCA System ROM : BIOS 400-7FF ROM   (    ) 400-7FF ROM  ( ) 1024 800-8FF RAM   (256 ) 900-9FF RAM  (256 ) A00-BFF ROM  ( ) C00-DFF ---  ,  800-9FF E00-FFF ROM  (  ) 

É necessário observar especificamente que, para jogos e programas em cartuchos, apenas parte da BIOS está disponível - aquela que contém o SP2 (desnecessário, em geral), imagens de números de 0 a 9 e um manipulador de interrupção padrão para vídeo.

VIDEO


Para gráficos, é usado o chip RCA CDP1861 - o chamado "Pixie".

O RCA Studio II padrão possui uma saída padrão apenas com antena (RF), no entanto, as pessoas o remodelam em composto para que a qualidade seja melhor (eu quase escrevi “para melhor reprodução de cores” :))

Tecnicamente, o controlador de vídeo fornece uma resolução máxima de 64x128 em duas cores (preto e branco). No entanto, isso requer 1024 bytes de memória de vídeo e, no Studio II, a quantidade total de RAM é de 512 bytes. Portanto, a resolução é 64 x 32 (o que requer 256 bytes) .A resolução horizontal (64) é fixa. Em uma linha de 64 pixels, 8 bytes são sempre exibidos e isso acontece por 14 ciclos do processador.

O manipulador de interrupção do BIOS é usado para exibir memória (US $ 900 - US $ 9ff) na tela. A interrupção é iniciada pelo controlador de vídeo e ocorre 60 vezes por segundo (NTSC). O processador do BIOS executa todas as operações necessárias - o programa executável precisa apenas alterar a memória de vídeo, na qual cada bit corresponde diretamente a um ponto preto ou branco (da esquerda para a direita, de cima para baixo).


No entanto, nada impede que você escreva seu próprio manipulador. O caso mais simples é a resolução de 64x128, pois é natural para um controlador de vídeo. Para ele, no manipulador, basta escrever o endereço da memória de vídeo em R0 (de onde virão os dados para a tela) e os bytes serão exibidos pelo próprio DMA, preenchendo o quadro. A situação é mais complicada com resoluções verticais que não 128. É necessário inserir atrasos e duplicar alterando R0 (consulte a descrição da fonte cdp1861 e BIOS).

Em princípio, você pode até obter uma resolução vertical variável, não produzir nada para uma parte da tela e também especificar ROM, não RAM (ou parcialmente ROM e parcialmente RAM) como memória de vídeo.Você também pode implementar a rolagem vertical, alterando a inicial em R0 O endereço a partir do qual os dados começam a ser emitidos para o controlador.

Observe que, na saída INT do controlador de vídeo, a unidade aparece duas linhas antes do feixe atingir a região visível. Portanto, o manipulador de interrupção geralmente inicia com um atraso que permite que você comece a exibir a memória na hora certa.


O controlador de vídeo também possui uma saída EFX, na qual 0 aparece por 4 linhas antes que o feixe apareça na região visível e depois nas últimas 4 linhas desta área. A saída EFX está conectada ao processador EF1 e seu status pode ser verificado com o comando B1 (BN1).

A expectativa típica de uma viga de retorno ao longo da estrutura é implementada da seguinte maneira:

 ... delay: bn1 delay ; wait for EFX in video chip ... 

Como observado acima, na ROM não há imagens de letras e sinais. No entanto, ainda existem números (afinal, em jogos internos, você precisa mostrar de alguma forma os pontos e o número do jogador). No entanto, mesmo aqui eles conseguiram salvar:


Como você pode ver, os números são agrupados para que os demais sejam obtidos de vários números adjacentes.

SOUND


Digamos apenas que há som. Mas não mais. O NE555 é conectado à porta de saída única de um bit do CDP1802 com uma fita e, em seguida, é conectado ao alto-falante embutido no decodificador.Quando uma unidade é fornecida à entrada RST NE555 (pelo comando do processador SEQ), ele começa a emitir um sinal sonoro a uma frequência de 625Hz. Quando zero (pelo comando REQ) - o sinal sonoro para. Na verdade isso é tudo. No entanto, ainda existe um capacitor devido ao qual, no início do guincho, a frequência diminui gradualmente pela metade no decorrer de 0,4 segundos (isto é, é obtido algum ruído adicional).


No manipulador de interrupção do BIOS padrão, além da parte responsável pelo vídeo, há uma peça que verifica o conteúdo de uma célula de memória específica e, se não houver zero, liga o guincho e começa a diminuir ciclicamente o conteúdo da célula $ 08CD (quando o zero é alcançado, o guincho é desativado). Portanto, você não pode se incomodar com a auto-gravação na porta, basta definir a duração do chiado e ocorrerá em segundo plano, sem interromper o programa:

  ldi $8cd & $ff plo rf ldi 250 ;   str rf ... 

O mesmo também pode ser feito manualmente (após desligar as interrupções):

 ;   sex r3 ; set X to R3 dis ; return X to R5, P to R3, 0-IE, R3=R3+1 db 53h ; forces X=5 P=3 - which is no change ;   seq ;   ldi 250 ; delay plo r6 delay: dec r6 glo r6 bnz delay ;   req ;    sex r3 ; set X to R3 ret ; return X to R5, P to R3, 1-IE, R3=R3+1 db 53h ; forces X=5 P=3 - which is no change 


PROGRAMAS


Na década de 1970, pouco mais de uma dúzia de jogos e vários outros programas foram escritos (principalmente pela própria RCA). Quase todos eles foram escritos não no assembler, mas no pseudo - código - na ROM do console, há uma máquina virtual especial para intérpretes ST2. É difícil dizer exatamente o que motivou essa decisão. Provavelmente, a idéia era economizar memória - os jogos realmente são significativamente menores em volume. Em geral, as orelhas ST2 crescem a partir de uma VM semelhante chamada CHIP-8 , usada em COSMACs. Embora as duas VMs não sejam compatíveis uma com a outra, já nos anos 2000 o intérprete CHIP-8 para o RCA Studio II foi gravado. Dada a extrema semelhança das arquiteturas, não é de surpreender que, como escreve o intérprete, jogos com COSMACs que não exigem muita memória sejam iniciados sem problemas no RCA Studio II.


Infelizmente, as VMs dessa arquitetura funcionam muito lentamente, o que deixa uma impressão indelével nos próprios jogos. Mais tarde, em 2013, Paul Robson escreveu cerca de uma dúzia de jogos - já em assembler e os distribuiu com a fonte.

DESENVOLVIMENTO


Inicialmente, de acordo com testemunhas, o desenvolvimento do RCA Studio II foi realizado mesmo sem montador - no COSMAC ELF e FRED2.

Atualmente, não há necessidade de sofrer assim. Existe um emulador decente para Windows - Emma , com um bom depurador (a propósito, ele emula não apenas o RCA Studio II, mas todos os COSMACs).


Como montador, tentei primeiro usar o cross-assembler a18, mas, por várias razões, acabei focando no asmx , que também possui scripts Python para gerar uma imagem pronta do cartucho (possui a extensão .st2).

Uma breve introdução ao assembler 1802 pode ser encontrada aqui . O test.asm mais simples para o RCA Studio II com um loop infinito ficaria assim:

  .include "1802.inc" .org 400h .db 4,2 ; SYS $402 start: br start ; some code .end 

Preste atenção à instrução ".db 4,2". Este é o endereço da primeira instrução executável, ou seja, ".db> (início), <(início)".

Implementação de loop simples:

  ldi 50 ;    D   plo r6 ;    D     r6 loop: dec r6 ; r6 = r6 -1 glo r6 ;     r6   D bnz loop ;    loop    D   

Usando as instruções SKIP:

 ; q = 0   $FF00 ,  q=1   $FF  loop: ghi r1 ; hi(r1) -> D lsz ;   2 ,   D  (..   seq) req ; 0 -> Q skp ;   1     (..   inc r1) seq ; 1 -> Q inc r1 ; r1 = r1 + 1 br loop ;  ... 

Para praticar em um montador limpo CDP1802, é conveniente usar o emulador de montador on-line asm80. A extensão do arquivo de origem gerado deve ser .a18

Para iniciar um aplicativo pronto em hardware real por natureza, existe um cartucho Multicart de 40 anos do RCA Studio II . Eu não tinha, mas o tnt23 refez um dos cartuchos disponíveis com um jogo para o chip EEPROM AT28C16 (2k x 8) instalado no soquete.


Então, para rodar no pedaço de ferro, inseri o chip no programador a cada vez, pisquei, reorganizei em um cartucho convertido e liguei o console. E assim sempre.



INTRODUÇÃO SEM SOMBRA



Para desenvolver a plataforma, escrevi 256 bytes de introdução (apresentada na Chaos Constructions'2018 no concurso de introdução minúscula ).

Ao contrário, digamos, do Vectrex , onde você pode obter uma imagem espetacular apenas desenhando uma curva ou no Videopac , onde a ROM já possui um conjunto de imagens de homenzinhos, aqui temos uma situação triste - comum, familiar a todos, gráficos raster, mas em preto e branco e resoluções abaixo do nada (64x32). Na ROM, não existem apenas imagens, mas até caracteres. Som - e isso é limitado a um ruído de 625Hz.

Assim, a música, todos os tipos de plasmas, luzes e, em geral, tudo o que envolve contornos não quadrados foi cancelada. O texto em qualquer forma também foi cancelado - não haveria espaço suficiente para as cartas.

Como resultado, foi decidido a) rolar b) algo repetido c) com velocidades diferentes, e ficou assim:


Como mencionado acima, não há rolagem de hardware no controlador de vídeo. No entanto, baixa resolução e preto e branco não têm apenas desvantagens, mas também vantagens - substituindo menos bytes.

Eu fiz rolagem linha por linha, usando o comando shlc (shift esquerdo com hifenização) - quando executado em um loop, verifica-se que o bit mais à esquerda do próximo byte é deslocado para a esquerda e não desaparece, mas é colocado no sinalizador de transporte (DF). Consequentemente, o próximo shlc em um loop o pega e o coloca no byte à esquerda. Acontece uma rolagem simples de toda a linha, das quais oito rolam em um ciclo (já que é conveniente obter padrões de nuvens e casas byte a byte)

 ... scrollret: sep r3 ; return from subroutine ;   scroll: ; set lines counter ldi LINES ; const -> D plo r10 ; D -> Rn.0 nextline: ; set bytes counter ldi BYTES_PER_LINE ; const -> D plo r7 ; D -> Rn.0 ; set carry to scroll glo r12 ; Rn -> D shr ; get one bit to set carry plo r12 ; D -> Rn.0 (save shifted byte) nextbyte: ldx ; Rx -> D shlc ; D = D << 1 (carry -> DF) stxd ; D -> M(Rx), Rx-- dec r7 ; Rn-- glo r7 ; Rn -> D bnz nextbyte dec r10 ; Rn-- glo r10 ; Rn -> D bnz nextline ; one line (8 bytes) scrolled, let's scroll next br scrollret ... 

Observe que o ponto de entrada para a sub-rotina está localizado no rótulo de rolagem e, para retornar, não apenas o sep r3 é executado, mas primeiro br scrollret e sep r3 a partir daí.

Isso é feito para deixar r14 (que é o contador de instruções dentro da sub-rotina) no estado correto e, em seguida, a sub-rotina pode ser chamada novamente e novamente (usando set r14).

Obviamente, nenhuma variável é salva durante as chamadas aqui - todos os registros de variáveis ​​são globais.

A sub-rotina de rolagem é chamada duas vezes no loop geral - a cada segunda vez para casas e a quarta vez para nuvens (elas rolam mais lentamente). O ciclo geral é sincronizado na direção inversa do feixe (estrada, casas, nuvens - tem tempo para desenhar, as estrelas são estáticas). No caso da estrada, apenas uma linha rola - as bordas da estrada são simplesmente desenhadas com linhas.

Por uma questão de interesse, tentei rolar a tela inteira - ela não se encaixa no movimento reverso do feixe a tempo.

Casas são definidas por padrões:

 ... house1: .db %00000000 .db %11111111 .db %10101010 .db %11111111 .db %10101010 .db %11111111 .db %00000000 .db 1 house2: .db %00000000 .db %00011111 .db %01110101 .db %01011111 .db %01110101 .db %00011111 .db %00000000 .db 1 ... 

e um tablet com um link para cada um:

 ... commands: .db house5 .db house2 .db house1 .db house3 ... 

Em um ciclo, esse rótulo é ordenado sequencialmente.

Diferentemente das casas, as duas nuvens, por simplicidade, representam um padrão que simplesmente rola ciclicamente.

Um certo número de bytes pode ser obtido devido à saída de nuvens de acordo com o mesmo princípio das casas, bem como devido às lacunas programadas entre os padrões (agora, esses dados estão apenas repetindo zeros nos dados).

No entanto, o problema também é que alguns registros são usados ​​pelo manipulador de interrupções - R0, R1, R2, R8, R9, R11 não podem ser alterados. E armazenar variáveis ​​na memória é um monte de bytes extras para gravá-los e lê-los (sem mencionar os ciclos de clock).

Idealmente, a rolagem provavelmente deve ser feita no manipulador de interrupções. No entanto, para isso, você teria que escrever seu próprio manipulador em vez do padrão. Isso seria mais correto (e, aliás, poderia liberar alguns registros R), mas provavelmente, no final, tudo junto não caberia em 256 bytes.

Quanto às estrelas, elas são estáticas, mas para desenhar alguns pontos que parecem localizados aleatoriamente, inesperadamente não era tão simples:

 ... loop: ldn r4 ; M[Rn] -> D ani %00000010 ; D AND const -> D bdf skip ; jump if carry ldi 0 ; const -> D skip: stxd ; D -> M(Rx), Rx-- glo r4 ; Rn -> D adi 47 ; D + const -> D plo r4 ; Rn -> D glo r15 ; Rn -> D bnz loop ... 

Aqui, em um ciclo, os dados são retirados do BIOS, que são reduzidos e os bits em excesso são mascarados. A máscara (para ani) e o tom (para adi) são escolhidos a dedo.

Quanto ao som, devido à incapacidade de alterar a frequência, os “bipes” do carro são simplesmente imitados.

A propósito - acho que esse intra é o primeiro trabalho demoscene para o RCA Studio II :)

EPÍLOGO


Após o Studio II, o RCA lançou várias instâncias do RCA Studio III . Diferenças em duas coisas - a cor apareceu (enquanto a resolução não mudou) e o som é melhor (você já pode emitir não uma, mas 255 frequências diferentes).


É interessante que ambas as máquinas sejam compatíveis entre si em ambas as direções, inclusive através do uso do mesmo código intermediário com o intérprete.

Sabe-se também que havia planos para o RCA Studio IV. Deveria ter aumentado a resolução para 64x128 e até mesmo um novo interpretador de pseudo-código já havia sido escrito.

Quanto ao CDP1802, esse microprocessador continua sendo produzido - primeiro foi fabricado pela Hughes, depois Intersil (Renesas)

Se você quiser saber mais sobre esse ramo peculiar da história do desenvolvimento da tecnologia de computadores, recomendo ao google as palavras " COSMAC" e "CDP1802 ".

Sitelinks


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


All Articles