sábado, 19 de janeiro de 2013

Pac-Mania 48/128K e compressão de dados

Pac-Mania é uma versão mais nova do venerado clássico PacMan, com gráficos 3D isométrico e a adição, no repertórios de movimentos do protagonista, do salto sobre os oponentes.


O programa original, apesar de ter um carregador em código de máquina, é composto por blocos salvos em BASIC:
  1. carregador BASIC "pacmania";
  2. carregador em código de máquina "l" CODE 24576,200;
  3. tela de carregamento "scrn" CODE 32768,6912;
  4. código de máquina principal "p" CODE 24576,40960;
  5. dados para banco de RAM 1 "m" CODE 49152,6000.
A adaptação para Beta não seria difícil, pois bastaria salvar os dados dos itens 3 a 5 no disco e criar um carregador em BASIC, se não fosse por um detalhe: o código de máquina principal é grande e obriga adotar um RAMTOP muito baixo. Com isto, o espaço para armazenar o carregador BASIC é muito pequeno.

Portanto o uso de compressão de dados seria uma solução adequada e, por isso, experimentei o ZX7 apresentado recentemente neste blog. Resolvi deixar a tela de carregamento intacta, pois uso-a no programa de menu para disco.

Os blocos dos itens 4 e 5 foram salvos no PC através da opção de menu File > Save binary data... do emulador Fuse e comprimidos com o ZX7. A compressão foi bem alta:
  • código de máquina principal, de 40450 para 15930 bytes;
  • dados para banco de RAM 1, de 6000 para 3278 bytes.
Note que não compactei todo o bloco de código de máquina principal, originalmente com 40960 bytes, mas somente os 40450 bytes iniciais. Omiti os últimos 510 bytes porque tinham todos valores 0, e também para reservar este espaço final cuja finalidade explicarei agora em detalhes.

O bloco de dados comprimido estará armazenado numa dada região da RAM. Considere uma variável chamada HL que contém o endereço inicial deste bloco. O conteúdo do endereço apontado por HL será descomprimido pelo programa DZX7 e salvo em outra região da RAM, cujo endereço será apontada pela variável chamada DE. Portanto o processo de descompressão consiste em pegar os dados (comprimidos) da posição de memória apontada por HL, para a posição, descomprimir e colocar na posição apontada por DE.

Tudo é mais fácil se as regiões de origem e de destino dos dados são independentes. Por exemplo, os dados para banco de RAM 1 podem ser armazenados na região 45874-49151 (3278 bytes) para 49152-55151 (6000 bytes). Neste caso, o HL varia de 45874 a 49151 e o DE varia de 49152 a 55151 e, como DE nunca assumirá quaisquer dos valores permitidos para HL, os dados descomprimidos não se sobreporão aos dados comprimidos.

Dados comprimidos
Dados descomprimidos




45874

(3278 bytes)

49151


49152



(6000 bytes)



55151





Entretanto para blocos grandes, como o código de máquina principal, não é possível reservar espaços na RAM separados entre os dados comprimidos e descomprimidos. Tem que haver obrigatoriamente uma sobreposição entre os blocos.

Esta sobreposição não deve ocorrer no início, pois os dados comprimidos serão corrompidos e o byte apontado por HL não terá o valor original, pois será reescrito pelo ponteiro DE.

Dados comprimidos
Dados descomprimidos




24576
24576
(15930 bytes)

40506


(40450 bytes)







65025





Alternativamente, os blocos podem ter a parte final coincidentes. Antes de DE atingir o início dos dados comprimidos, não ocorrerá reescrita deste bloco. Mas mesmo quando começar a se escrever a partir deste endereço (no exemplo abaixo, em 49096), tem uma boa chance deste dado já ter sido usado e não ser mais necessário.

Dados comprimidos
Dados descomprimidos





24576





(40450 bytes)


49096

(15930 bytes)

65025
65025





O problema surge quando se aproxima ao final de ambos os blocos, pois DE e HL começam a ter valores próximos. Portanto é melhor que haja um deslocamento entre os finais dos blocos de dados comprimidos e descomprimidos, para garantir que os dados ainda a serem processados não sejam corrompidos.

Dados comprimidos
Dados descomprimidos





24576







(40450 bytes)


49606



(15930 bytes)
65025


65535


Com isto, garante-se que DE e HL nunca tenham o mesmo valor, pois o primeiro sempre terá um valor menor que o segundo e garante-se a integridade dos dados. A única questão restante é de quantos bytes deve ser a defasagem entre os dois blocos; segundo Einar, seria ao redor de 100 bytes.

Em todo caso, como cautela sempre é bom, conferi o dado descomprimido com o original e, felizmente, coincidiram.

Para finalizar a adaptação, salvei no TRD a tela, um bloco de bytes contendo os dados comprimidos e o programa para descompressão e o carregador BASIC. Os detalhes dos procedimentos e os códigos fontes estão disponibilizados.

Os arquivos Hobeta encontram-se no Google Drive e no 4 Shared. Também fiz versões TAP e TZX pois, com a compressão, até o carregamento via fita cassete ficará mais rápido (vide este subdiretório).


Nenhum comentário:

Postar um comentário

Seu comentário é bem vindo, mas peço que use este espaço adequadamente.