- PowerBASIC: Desenvolvido especificamente para o Turbo R, pois precisa do mecanismo de Shadow ROM pra funcionar. Ao ser carregado, o editor do BASIC passa a usar o V9990. O modo de vídeo utilizado permite textos de 64x24 caracteres, mas é um tanto lento (é possível ver a cor de frente ou fundo do texto sendo alterada caractere por caractere). O PowerBASIC apenas implementa os modos de video baseados em Tiles (P1 e P2), com direito a comandos de manipulação de sprites (o que é ótimo). O desenvolvedor original foi o Henrik Gilvad da Sunrise (o criador da GFX9000) e aparentemente o desenvolvimento foi interrompido.
- GBASIC: Desenvolvido pensando num MSX2 (e portanto não funciona num MSX1) o editor de código permanece no VDP interno, (e isso de certa forma é positivo porque é um modo de texto rápido e possui 80 colunas). Suporta apenas os modos Bitmapped mas tem suporte para numeros grandes (maiores que 16 bits, que são necessários para endereçar a VRAM). O desenvolvedor original foi o Koen van Hartingsveldt da Sunrise (o criador da Video9000) e o desenvolvimento estava parado até ter sido transferido para a TNI (Patriek Lesparre e Albert Beevendrop), porém ainda nao houve um release com novas funções.
Diante destas limitações, os pouquissimos programadores que se aventuram a mexer com o V9990 o fazem acessando diretamente. No nosso caso não será diferente, e iremos fazer isso a partir do BASIC (exatamente o que o Kai Magazine fez no jogo Myths & Dragons). Quando tivermos suporte completo para o V9990, isso não será mais necessário.
Como então nós vamos acessar ao V9990? Através das portas de comunicação, mapeadas no barramento de I/O do Z80:
IMPORTANTE: W significa que a porta é somente escrita e não retorna informação válida quando lida; R significa que a porta é somente leitura e não recebe nenhum valor se tentarmos escrever nela; e R/W significa que a porta aceita tanto leituras como escritas.
- P#0 VRAM Data (R/W)
- P#1 Palette Data (R/W)
- P#2 Command Data (R/W)
- P#3 Register Data (R/W)
- P#4 Register Select (W)
- P#5 Status (R)
- P#6 Interrupt Flag (R/W)
- P#7 System Control (W)
- P#8 Primary Standard Kanji ROM lower order Address (W)
- P#9 Primary Standard Kanji ROM higher order Address (W)
- P#9 Primary Standard Kanji ROM data (R)
- P#A Secondary Standard Kanji ROM lower order Address (W)
- P#B Secondary Standard Kanji ROM higher order Address (W)
- P#B Secondary Standard Kanji ROM data (R)
- P#C~F Reserved
No MSX, o Base address (ou seja, o endereço no qual está endereçada a primeira porta do VDP) é &H60, ou seja, se você quiser acessar a porta de Status, você fará uma leitura no endereço &H65.
Uma observação importante sobre a porta &H6F: embora ela não seja utilizada pelo V9990, ela foi implementada pela GFX9000 para controlar o funcionamento do chip V7040, que tem é o encoder de vídeo composto e S-Video utilizado por ela mas já implementa o RGB Switch necessário ao Superimpose. Quando surgiu a Video9000, essa mesma porta foi expandida para controlar os sinais de ativação do Genlock e seletor de entrada de vídeo para superimpose/digitize do V9990.
Mas além de conhecer as portas, é preciso conhecer os registradores, pois também são necessários para todo tipo de tarefas que serão executadas no V9990. São elas:
- R#0~2 VRAM Write Address (W)
- R#3~5 VRAM Read Address(W)
- R#6~7 Screen Mode (R/W)
- R#8 Control (R/W)
- R#9~12 Interrupt (R/W)
- R#13 Palette Control (W)
- R#14 Palette Pointer (W)
- R#15 Back Drop Color (R/W)
- R#16 Display Adjust (R/W)
- R#17~24 Scroll control (R/W)
- R#25 Sprite Pattern Generator Base Address (R/W)
- R#26 LCD Control (R/W)
- R#27 Priority Control (R/W)
- R#28 Sprite Palette Control (W)
- R#32~52 Command (W)
- R#53~54 Command (R)
Para escrever em um Registrador, primeiro você escreve o número do registrador na porta P#4, depois escreve/lê o dado que desejado usando a porta P#3.
Agora que sabemos disso, podemos começar a trabalhar. Mas antes de começar a desenhar na tela do V9990, você precisa inicializar o VDP, informando parâmetros de funcionamento como origem do clock, modo de vídeo, se vai haver superimpose e tamanho da VRAM só para citar alguns. Em seguida dependendo do modo de vídeo você ainda precisa definir quais são as cores da palheta de cores, do contrário você vai desenhar na tela e ela vai continuar preta (ou branca em alguns casos) pois todos os registradores de cor irão conter os mesmos valores para todas as cores.
Somente depois desses cuidados que você irá ver algum resultado na tela depois de escrever na VRAM do V9990.
Em GBASIC isso já foi implementado para os modos Bitmapped, bastando incluir as seguintes linhas no seu programa:
10 BLOAD "GBASIC.BIN",RAs linhas acima carregam o GBASIC na memória e a partir disso passamos a contar com diversos comandos BASIC precedidos pela letra G. a segunda linha, inicializa o V9990 no modo B1, com uma palheta de 16 cores que suporta 3 bits por componente, exatamente como na SCREEN 5 de qualquer MSX2. Para suportar cores com 5 bits por componente, devemos usar "GSCREEN 15".
20 GSCREEN 5
Para fazer a mesma coisa em BASIC comum (ou em assembly), os seguintes comandos são necessários:
100 OUT &H6F,24Com essas linhas já é possivel "desenhar" no V9990 e ver o resultado. Explicando:
110 OUT &H67,0
120 OUT &H64,8:OUT &H63,162
130 OUT &H64,6:OUT &H63,133
140 OUT &H64,7:OUT &H63,0
150 OUT &H64,14:OUT&H63,0
160 OUT &H61,128:OUT &H61,0:OUT &H61,0
161 OUT &H61,0:OUT &H61,0:OUT &H61,0
162 OUT &H61,4:OUT &H61,27:OUT &H61,4
163 OUT &H61,13:OUT &H61,31:OUT &H61,13
164 OUT &H61,4:OUT &H61,4:OUT &H61,31
165 OUT &H61,9:OUT &H61,13:OUT &H61,31
166 OUT &H61,22:OUT &H61,4:OUT &H61,4
167 OUT &H61,9:OUT &H61,27:OUT &H61,31
168 OUT &H61,31:OUT &H61,4:OUT &H61,4
169 OUT &H61,31:OUT &H61,13:OUT &H61,13
170 OUT &H61,27:OUT &H61,27:OUT &H61,4
171 OUT &H61,27:OUT &H61,27:OUT &H61,18
172 OUT &H61,4:OUT &H61,18:OUT &H61,4
173 OUT &H61,27:OUT &H61,9:OUT &H61,27
174 OUT &H61,22:OUT &H61,22:OUT &H61,22
175 OUT &H61,31:OUT &H61,31:OUT &H61,31
- Na linha 100, escrevemos no registrador de controle da GFX9000 e Video9000 (e isso é importante para compatibilidade tanto passada quanto futura, ainda que esta porta não tenha sido implementada na PowerGraph). O valor 24 significa que o Genlock está ativo a tela irá exibir tanto a imagem do VDP interno, quanto a imagem do V9990 sobre ela. (isto também é suportado pelo openMSX, para tanto basta utilizar a extensão VIDEO9000 e digitar no console "set videosource video9000"). Caso você queira explicitamente impedir o superimpose (desta forma não irá enxergar a imagem do VDP interno do MSX por trás da imagem do V9990), substitua este valor por 0.
- Na linha 110, escrevemos na porta de controle que será utilizado o clock proveniente do pino XTAL1. No MSX este pino recebe um clock de 21,47MHz. Nos modos de vídeo B2 e B4, é necessário um clock diferente, e para isto deverá ser escrito o valor 1 nesse registrador.
- Na linha 120, selecionamos o registrador R#8 (registrador de controle) o valor 162, que significa que o V9990 passa a exibir imagem, que o tamanho da VRAM instalada é 512k, e que a informação de transparência será sinalizada pelo pino /Ys do V9990. Caso você queira forçar que a imagem não seja transparente, você deverá usar o valor 130 ao invés de 162.
- Nas linhas 130 e 140, escrevemos nos registradores R#6 e R#7 os valores necessários para ativar um modo de vídeo. Neste caso, para ficar igual ao primeiro exemplo, ativamos o modo equivalente ao "GSCREEN 15".
- Na linha 150 escrevemos no registrador R#14 para avisar ao V9990 que as próximas escritas na porta P#1 (Palette Data) deverão ser armazenadas na palheta de cor numero 0.
- Nas linhas 160~175 escrevemos sequencialmente os valores dos componentes R, G e B de cada cor da palheta, de 0 a 15. Ao somar 128 ao valor do componente vermelho de uma cor, definimos que aquela cor é transparente, portanto ao contrário do que acontecia nos VDPs anteriores, a cor 0 não é obrigatoriamente transparente, e qualquer uma das 16 cores da palheta pode ser definida como transparente. Os valores contidos nesse programa de exemplo são os valores das cores padrão de um Turbo-R. Sim, mais um detalhe: Assim como nas escritas na VRAM dos VDPs anteriores, se fizermos diversas escritas na mesma porta, o V9990 se encarrega sozinho de incrementar o ponteiro do endereço de escrita; neste caso, a primeira escrita é no componente vermelho da cor 0 (R0 de agora em diante), a segunda é em G0, a terceira em B0, a quarta em R1, a quinta em G1 e assim sucessivamente.
(Obviamente as linhas do programa acima podem ser condensadas em uma unica linha - com o limite de até 255 caracteres por linha. Eu deixei desta forma apenas para melhorar a legibilidade do código.)
E (FINALMENTE!) já podemos desenhar qualquer coisa na tela. Eu sugiro o seguinte código:
Se estivessemos usando o GBASIC, seria algo assim:
10 BLOAD "GBASIC.BIN",RO que fizemos aqui foi plotar pontos na tela a partir do endereço absoluto da VRAM. Assim como na SCREEN 5, cada ponto da GSCREEN 15 ocupa 4 bits na VRAM, então o valor armazenado no endereço 0 define os pixels (0,0) e (0,1) da tela. O endereço 1 define os pixels em (0,2) e (0,3), e assim sucessivamente. Como a GSCREEN 15 possui 512 pixels em cada linha (apesar de só exibir 256 ao mesmo tempo), o pixel (1,0) está armazenado imediatamente ao byte que contém o pixel (0,511), no caso, iremos gravar na posição 256 da VRAM pra definir os pixels (1,0) e (1,1). E assim
20 GSCREEN 15
30 GVPOKE 0,0:GVPOKE 1,255:GVPOKE 2,255:GVPOKE 3,0
40 GVPOKE 256,15:GVPOKE 257,0:GVPOKE 258,0:GVPOKE 259,240
50 GVPOKE 512,240:GVPOKE 513,240:GVPOKE 514,15:GVPOKE 515,15
60 GVPOKE 768,240:GVPOKE 769,0:GVPOKE 770,0:GVPOKE 771,15
70 GVPOKE 1024,240:GVPOKE 1025,240:GVPOKE 1026,15:GVPOKE 1027,15
80 GVPOKE 1280,240:GVPOKE 1281,15:GVPOKE 1282,240:GVPOKE 1283,15
90 GVPOKE 1536,15:GVPOKE 1537,0:GVPOKE 1538,0:GVPOKE 1539,240
100 GVPOKE 1792,0:GVPOKE 1793,255:GVPOKE 1794,255:GVPOKE 1795,0
110 GOTO 110
sucessivamente, como já acontece na SCREEN 5. Quem só mexeu com SCREEN 2 infelizmente não há uma conexão entre a forma que ela e esses dois modos gráficos funcionam, portanto eu tenho que confiar que essa explicação foi suficiente até o momento que eu for explicar os modos P1 e P2.
E, finalmente, para fazer o mesmo código em BASIC puro, sugiro o seguinte código:
100 OUT &H6F,24A partir da linha 200 temos o código que executa os GVPOKEs do código anterior.
110 OUT &H67,0
120 OUT &H64,8:OUT &H63,162
130 OUT &H64,6:OUT &H63,133
140 OUT &H64,7:OUT &H63,0
150 OUT &H64,14:OUT&H63,0
160 OUT &H61,128:OUT &H61,0:OUT &H61,0
161 OUT &H61,0:OUT &H61,0:OUT &H61,0
162 OUT &H61,4:OUT &H61,27:OUT &H61,4
163 OUT &H61,13:OUT &H61,31:OUT &H61,13
164 OUT &H61,4:OUT &H61,4:OUT &H61,31
165 OUT &H61,9:OUT &H61,13:OUT &H61,31
166 OUT &H61,22:OUT &H61,4:OUT &H61,4
167 OUT &H61,9:OUT &H61,27:OUT &H61,31
168 OUT &H61,31:OUT &H61,4:OUT &H61,4
169 OUT &H61,31:OUT &H61,13:OUT &H61,13
170 OUT &H61,27:OUT &H61,27:OUT &H61,4
171 OUT &H61,27:OUT &H61,27:OUT &H61,18
172 OUT &H61,4:OUT &H61,18:OUT &H61,4
173 OUT &H61,27:OUT &H61,9:OUT &H61,27
174 OUT &H61,22:OUT &H61,22:OUT &H61,22
175 OUT &H61,31:OUT &H61,31:OUT &H61,31
200 OUT &H64,0:OUT &H63,0:OUT &H64,1:OUT &H63,0:OUT &H64,2:OUT &H63,0
210 OUT &H60,0:OUT &H60,255:OUT &H60,255:OUT&H60,0
220 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,1
230 OUT &H60,15:OUT &H60,0:OUT &H60,0:OUT&H60,240
240 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,2
250 OUT &H60,240:OUT &H60,240:OUT &H60,15:OUT&H60,15
260 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,3
270 OUT &H60,240:OUT &H60,0:OUT &H60,0:OUT&H60,15
280 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,4
290 OUT &H60,240:OUT &H60,240:OUT &H60,15:OUT&H60,15
300 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,5
310 OUT &H60,240:OUT &H60,15:OUT &H60,240:OUT&H60,15
320 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,6
330 OUT &H60,15:OUT &H60,0:OUT &H60,0:OUT&H60,240
340 OUT &H64,0:OUT &H63,0:&H64,1:OUT &H63,7
350 OUT &H60,0:OUT &H60,255:OUT &H60,255:OUT&H60,0
- Na linha 200 ele define o ponteiro de endereço para escrita na VRAM para o endereço 0 (no V9990, os endereços de VRAM tem 19 bits - 2ˆ19=512k) Um numero de 19 bits precisa de 3 bytes para ser armazenado, então o registrador de endereços é dividido em 3 partes e, assim como no Z80, os numeros são organizados conforme o padrão little endian (o byte menos significativo vem antes do byte mais significativo). Então, o R#0 contem os bits 0~7, o R#1 contém os bits 8~15, e o R#3 os bits 14~18. Para começar escrever a partir da posição 0 da memoria, gravamos 0, 0 e 0 nesses registradores.
- Na linha 210, assim como ja vimos nas linhas 160~175 e na programação dos VDPs anteriores, vemos 3 escritas em sequencia na P#0. A cada escrita o VDP incrementa sozinho o ponteiro do endereço de memória, então escrevemos os primeiros endereços da VRAM com apenas 4 OUTs. Para quem está acostumado com BASIC pode parecer que estamos gastando mais instruções ao fazer dessa forma, mas quem já é versado em programação nos VDPs anteriores sabe que a cada (G)VPOKE o BASIC seta novamente o ponteiro de escrita da VRAM, portanto fazendo dessa forma estamos na verdade economizando 18 escritas na porta do VDP. (Uma vez que para cada escrita aleatória gastamos 6 escritas pra definir o ponteiro mais uma para enviar o dado)
- Na linha 220, repetimos o processo da linha 200, mas com uma otimização: não precisamos definir novamente o R#3 porque ele não foi incrementado, portanto, duas escritas a menos.
- Na linha 230, repetimos o processo da linha 210.
- Nas linhas 240~350, repetimos todo o processo acima.
Ao executar os códigos, veremos um desenho de 8X8 pixels no canto superior esquerdo da tela. Notem que o resultado de ambas as listagens é exatamente o mesmo.
Para o leitor que chegou até aqui, deixo a sugestão de alterar o código acima para imprimir outros desenhos ponto a ponto e se possível utilizando cores. Nos vemos no próximo capítulo. até lá!