"O homebrew do Canal F seria como programar sprites através de jumpers de hardware ..."
/ chadtower, fórum de atariada /
O console do jogo
Fairchild Channel F , também conhecido como VES, apareceu em novembro de 1976. Ao contrário de seus antecessores, como o pingue-pongue, o tênis (na mesma linha - o "Video Sports" soviético)), tinha uma diferença muito significativa - a presença de um microprocessador e cartuchos com programas. Antes disso, os jogos nos consoles eram implementados com lógica estrita - o programa, no sentido moderno, estava ausente lá.
O canal Fairchild F foi lançado até 1983. Durante esse período, mais de um quarto de milhão desses consoles foram vendidos e cerca de 30 a 40
jogos foram lançados ,
alguns dos quais já estavam nos anos 2000.
Falando sobre a superioridade em termos de uso de um microprocessador, vale a pena notar que o RCA Studio II, sobre o qual falei em um artigo anterior, estava apenas alguns meses atrasado, mas acabou sendo significativamente mais fraco que o Canal F, razão pela qual falhou nas vendas. No entanto, a aparição, menos de um ano depois, Atari VCS - e substituiu o Canal F. do mercado.
O desenvolvimento de Fairchild_Channel_F, como tal, não foi. No Sistema II e em vários clones, como Saba Videoplay 2 (1979), as diferenças estavam principalmente no corpo, nos joysticks (a propósito, todos entendiam, exceto nas posições habituais, na rotação do botão) e no número de chips. Arquitetonicamente, tudo era quase idêntico.
O que é o canal F?
CPU
O processador, nas tradições da época, foi produzido pela mesma empresa Fairchild que o próprio console e é chamado F8
en.wikipedia.org/wiki/Fairchild_F8 . Este é um processador de 8 bits de 1974, operando a uma frequência de 1,8 MHz (uma instrução leva de 1 a 6 ciclos de clock).
No entanto, ele pode ser chamado de microprocessador apenas com uma extensão, pois esse processador consiste em dois chips - um dispositivo de computação 3850CPU contendo ALU, uma bateria, 64 bytes de SRAM, a lógica necessária para executar instruções, duas portas (não há barramento de endereço!) E 3851PSU (Programável Storage Unit), que contém 1kb de ROM (usado para BIOS), um ponteiro de instrução, esquemas de endereçamento de memória, interrupções, um timer (as interrupções e um timer não são usados especificamente no Canal F).
Mais tarde, apareceu o chip F3859, que combinava a CPU e a PSU no mesmo chip e o Mostek 3870 - uma versão ligeiramente melhorada, lançada até a década de 1990. No entanto, essa é outra história. Curiosamente, às vezes o F8 é chamado de microcontrolador (em particular, devido à presença de um timer e portas) e é referido como o ancestral da família Intel MCS-48 (8048).
Além do Canal F, o processador F8 também foi usado no computador
VideoBrain e no computador de xadrez
CompuChess . Em geral, é surpreendente que haja muito pouca informação sobre esse processador. Com exceção de algumas descrições de Fairchild e o código fonte de vários jogos e exemplos especificamente para o Canal F, não há mais nada. Parece que este processador não foi usado em nenhum outro lugar, o que parece incrível (dado que suas versões avançadas foram lançadas há algum tempo). Assumirei que todos os outros dispositivos em que foi usado foram para fins militares.
Agora um pouco sobre os recursos do processador. Reflita sobre o conjunto e as funções de seus registros. Eu acho que essa é uma das arquiteturas mais confusas que existiam na época (as modernas podem provavelmente se estender, mas a comparação será incorreta, porque elas foram projetadas para compiladores. As pessoas vivas trabalhavam com o F8).
Existem muitos registros no processador. Além da bateria de 8 bits A e do registro de bandeira W (I, O, Z, C, S), também há um "bloco de notas" - 64 células de oito bits com várias funções.
As nove primeiras células são usadas como registradores de uso geral R0-R8 em comandos como 'lr a, 7 "(carrega o conteúdo do registro R7 na bateria). Observe que a letra R não é indicada - apenas o número do registro é escrito. O que exatamente se quer dizer, o número ou o número deve estar claro a partir do contexto. Digamos, no caso da instrução lr, simplesmente não pode haver números. E se, por exemplo, "li 7" (carrega uma constante na bateria), então é exatamente um número, não um registro.
As células 9, 10-11 (H), 12-13 (K), 14-15 (Q) são projetadas para salvar outros registros em diferentes situações, como chamar subprogramas.
Os registradores R16-R63 são acessíveis apenas por meio de um registro de índice ISAR especial (registro indireto de endereços do Scratchpad), como seis buffers de oito bytes formados a partir das células 16-23, 24-31, 32-39, 40-47, 48-55, 56-63 .
O ISAR de seis bits é dividido em duas partes de 3 bits. Ao aumentar ou diminuir o ISAR em um, apenas os 3 bits inferiores são afetados - ou seja, o endereçamento é realizado dentro de um dos seis buffers de oito bytes mencionados (ao mesmo tempo, o final do buffer pode ser rastreado pelas instruções especiais de ramificação condicional br7).
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
Nesse caso, “d” na instrução “lr d, a” não é o nome do registro, mas um sinal de que o ISAR precisará ser reduzido (“i” - aumente, “s” - deixe inalterado).
Existe outra maneira de endereçamento indireto - através do registro DC0 (contador de dados):
dci data_addr ; data_addr -> DC0 lm ; [data_addr] -> A, DC0 + 1 -> DC0 ... data_addr: db 0,1,2,3,...
Se você precisar transferir dados de uma área de memória para outra, o comando xdc é usado adicionalmente, que troca o conteúdo dos registradores DC0 e DC1. I.e. lemos a partir do endereço apontado por DC0, depois fazemos xdc e escrevemos no endereço que o DC1 agora aponta. Então, novamente xdc, etc. I.e. DC1 é um tipo de registrador sombra para armazenar uma cópia do DC0. Acessá-lo diretamente (exceto o comando xdc) é impossível.
Os exemplos acima ilustram apenas parte das possibilidades em termos de abordagem; de fato, existem mais.
Também no F8 existem quatro portas - 0,1,4,5, nas quais você pode escrever com o comando out e ler com o comando in. No Canal F, as portas são usadas para gerar gráficos, sons e ler o status do joystick.
Não vou me debruçar sobre outras instruções, como aritmética, transições etc. - elas são razoavelmente padrão. Observo apenas que a escolha de registradores sobre os quais você pode executar ações é muito limitada; portanto, o código cresce rapidamente devido à necessidade de mover valores constantemente para frente e para trás.
Não há subtração (há apenas adição). As instruções de decremento (ds) e incremento (inc) por unidade são assimétricas. ds funciona apenas com os registradores r0-r8, inc - apenas com a bateria.
O salto incondicional estraga a bateria.
Um exemplo de um loop regular:
li 25 ; (r4) number of iterations lr 4,a next: ds 4 ; r4-- bnz next ; until r4 == 0
Rotinas
Como o F8 não possui uma pilha de hardware, há dificuldades com as chamadas de subprograma aninhadas. Uma chamada e retorno normais são assim:
; ...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
Aqui PC0 é um ponteiro de instrução regular. PC1 - o chamado "registro de pilha". Não tem nada a ver com a pilha, apenas PC0 é salvo quando a sub-rotina é chamada.
Se outra sub-rotina é chamada de sub, o endereço de retorno é substituído e precisa ser complicado (salve o primeiro endereço de retorno no 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
Se você também precisar de um terceiro nível de aninhamento, tudo ficará completamente triste (no BIOS para isso, existem até duas rotinas especiais - pushk e popk).
A recomendação geral é tentar substituir chamadas de sub-rotina por macros. Obviamente, se não houver restrições estritas no tamanho do código.
Não há pilha de hardware no F8. Se necessário, é implementado programaticamente - através do ISAR e buffers.
Escrever na RAM não é muito relevante (por falta de um), mas é assim:
li $FF ; set value dci $3800 ; set target address st ; write
A memória
Embora isso pareça um pouco estranho, não há RAM no Fairchild Channel F. Os dois kilobytes existentes da memória de vídeo (MK4027) não são exibidos no espaço de endereço e, na verdade, não são legíveis, são gravados nas portas. Os registros do microprocessador, até 64, dificilmente são considerados corretos para a RAM.
O programa executável é armazenado em cartuchos de ROM removíveis, geralmente com capacidade de 2kb (alguns jogos modernos usam cartuchos de 3k, 4k e 5k). Além disso, existe um chip de processador embutido, 1KB BIOS ROM, contendo um jogo simples, como o tênis, algumas rotinas úteis e imagens de vários personagens.
No espaço de endereço, o BIOS está localizado de US $ 0000 a US $ 07ff, a ROM do cartucho - de US $ 0800.
Gráficos
As capacidades gráficas do canal F são muito primitivas, uma vez que simplesmente não existe um controlador de vídeo na forma de um chip separado - tudo é implementado na lógica usual, como registros de turnos, portões e amplificadores operacionais. É bastante incomum que fontes diferentes mencionem resoluções diferentes, e há muitas opções. O fato é que os 2 kilobytes disponíveis de memória de vídeo implicam uma resolução de 128 x 64, mas, na realidade, isso está longe de ser o caso. Em primeiro lugar, depende muito de qual área da imagem que está sendo formada nessa TV em particular é visível (por causa das quais as 4 primeiras colunas não são usadas oficialmente). Em segundo lugar, as últimas colunas são usadas sob a paleta. Terceiro, parte da memória não é usada.
Como resultado, a resolução real pode ser estimada em aproximadamente 95 x 58 pixels com 8 cores (o que, no entanto, é muito melhor que o RCA Studio II, com 64x32 em preto e branco).
A maioria dos consoles é lançada na versão NTSC, mas o PAL também existe. Não há diferenças práticas, como se costuma dizer (o número de linhas é o mesmo).
Essencialmente, um ferro tão simples permite desenhar pontos na tela. Embora o número total de cores exibidas seja 8, no entanto, apenas quatro podem ser exibidas em uma linha (você pode arbitrariamente chamar isso de paleta). A paleta é definida individualmente para cada linha e é armazenada em um local bastante estranho - nas colunas 125 e 126 de cada uma das linhas (que, em qualquer caso, estão fora da área visível). Alterar a paleta é, respectivamente, desenhando pixels nessas duas colunas.
(a área de memória de vídeo realmente visível na tela e a área em que a paleta está definida são destacadas em amarelo)
Como observado acima, há apenas uma maneira de gravar dados na VRAM - através das portas. Isso indica a cor, coluna, linha:
X é gravado na porta 4, Y na porta 5, a cor na porta 1, após a qual os dados são transferidos gravando uma constante na porta 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
É necessário um atraso para que tudo possa ser gravado; caso contrário, o próximo ponto pode não ser desenhado. Na versão oficial, 4 ainda é adicionado à coluna e linha (omitido por simplicidade)
Preencher a tela inteira com pontos (em um loop) leva cerca de um segundo. É importante observar que, além da atualização extremamente lenta da tela, também há o fato de que não há como esperar que a viga retorne através do quadro. Assim, mesmo um pequeno redesenho é inevitavelmente acompanhado por um piscar de olhos.
Agora sobre a paleta. A rigor, para cada linha, existem dois modos - preto e branco (quando o fundo é preto e o primeiro plano é apenas branco, independentemente do pixel desenhado) e cor.
No modo de cor de primeiro plano, sempre há três - vermelho, verde e azul (rgb). Além disso, uma das três cores de fundo - cinza, azul claro, verde claro.
Para definir a paleta nas colunas 125 e 126, escreva os seguintes 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
Em jogos típicos, eles costumam fazer isso: primeiro eles definem um certo contexto geral, para o qual você pode usar o procedimento BIOS pronto:
li $c6 ; $21 - b/w palette, fill with black. $c6 - color palette, fill with gray lr 3, A pi clrscrn ; clrscrn BIOS call
Em seguida, se necessário, faça uma faixa com uma paleta de preto e branco (por exemplo, para exibir a pontuação do jogo com números brancos em fundo preto)
E então eles colocam pixels em uma das três cores (se o fundo for cinza, respectivamente - r, g, b). Como resultado, é claro que existem 8 cores, mas colocar em um local específico um ponto de uma cor arbitrária é tão fácil - é impossível.
Aqui está um conjunto de fotos que dão uma idéia das cores e suas combinações.
Na verdade, com isso todos os gráficos, como tal, terminam - tudo o que você deseja fazer é desenhar pixels, e manualmente. Em rotinas úteis, o BIOS possui saída de caracteres. No entanto, por razões de economia de espaço, na ROM há apenas imagens de números e caracteres individuais, com tamanho de 5x8 pixels:
No entanto, o procedimento para sua retirada é útil e pode ser usado da seguinte maneira:
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
Na versão acima, os dois dígitos superiores no registro r0 determinam a cor (10 - vermelho, 11 - verde, 01 - azul, 00 - transparente), o restante - o número de série do caractere (0 1 2 3 4 5 6 7 8 9 G? T SPACE MX BLOCO: - centro || esquerda || `), começando do zero. Os registradores r1 e r2 são colocados, respectivamente, em uma coluna e em uma linha.
Uma opção mais prática é não pensar em 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 ter uma ideia da plataforma, escrevi uma
introdução de 256 bytes para o pequeno concurso de introdução na
Chaos Constructions'2019 . Nada de especial, mas preste atenção ao motivo pelo qual a paleta linha a linha é usada lá. Uma faixa horizontal rastejante, por assim dizer, destaca a linha que está embaixo dela, substituindo temporariamente todo o fundo por preto e todos os pixels por branco. Como você não precisa sobrescrever os pixels em si (e não precisa restaurá-los posteriormente), é possível fazer essa “luz de fundo” muito rapidamente e sem tremulação.
O segundo ponto são as letras "CC". Como as letras “C” não estão no BIOS, a sobreposição das letras GG e o número 1 são usadas para obter o “CC” inverso.
Som
O som está ruim. Oficialmente, existem três sons - 120Hz, 500 Hz e 1 KHz. De fato, obter algo diferente de cliques e um chiado agudo é problemático. Além disso, eles dizem que entre máquinas PAL e NTSC, bem como entre versões antigas e novas, o som também é diferente. No entanto, para jogos típicos, basta. Som ligado e desligado através das portas:
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
As pessoas até se divertiam tocando música.
As melhores amostras remotamente se assemelham ao PC-Speaker. É verdade que não há sentido prático de qualquer maneira - todos os recursos do processador vão para a música, nada de especial pode ser feito.
Ferramentas de desenvolvimento
Atualmente, há uma
seleção pronta do software necessário chamado "Development Pack".
Isso inclui montador DASM, desmontador, emulador MESS (com depurador). Tudo isso funciona sem problemas, pelo menos no Windows 7.
Parâmetros para montagem e inicialização:
dasm.exe test.asm -f3 -otest.bin messd channelf -cartridge %cartPath%\test.bin -w -effect sharp -r 640x480 -ka
O emulador é muito bom, embora o depurador seja extremamente estranho. Não consegui configurar a nova versão do MAME / MESS imediatamente (notei que configurar o MAME para uma plataforma impopular que supostamente suporta é sempre uma tarefa não trivial).
O emulador assume que a resolução da região visível corresponde a minx = 5, minY = 5, maxX = 105, maxY = 61
Como não há prazer em escrever algo sob o emulador sem ter testado o resultado ao vivo, tive que resolver o problema com o emulador de ROM. A meu pedido, a
tnt23 fez um cartucho especial (Alexander Novozhilov imprimiu um estojo para ele) no qual a EEPROM 28C16A está inserida. Devido às peculiaridades do endereçamento F8, eu ainda tinha que comprar um antigo chip Fairchild 3853 no eBay. Como resultado, foi possível programar a EEPROM para ver como o código fica em uma máquina ativa.
Além disso, o tnt23 conectou uma saída S-Video do canal F (normalmente, ela só podia ser conectada a uma TV pela entrada da antena), o que melhorava bastante a qualidade da imagem e a reprodução de cores.
História sobre Fairchild Channel F:
Recursos