Despues de leer el articulo del RLE de santiago romero, he reescrito el codigo de la rutina descompresora y he creado la rutina compresora.
He realizado la compresion de la rom de 48K, y posterior descompresion y salen identicas.
Hay un pequeño truquito con el LDI y el RET PO (un flash no muy usado, pero que usa LDI para indicar BC=#0000) y me he ahorrado algunos bytes
rutina compresora 62 bytes
rutina descompresora 26 bytes
Código:
;; Creada por Z80user
;; Compresor / Descompresor RLE
;; Comprime y Descomprime un bloque de datos RLE de memoria a memoria.
;;
;; Entrada a la rutina COMPRESORA:
;; HL = destino de los datos RLE.
;; IX = datos a comprimir
;; BC = tamaño de los datos a comprimir.
;; Salida
;; AF,DE desconocido
;; HL = HL+longitud de los datos comprimidos
;; IX = IX+BC
;;
;; Entrada a la rutina DESCOMPRESORA:
;; HL = dirección origen de los datos RLE.
;; DE = destino donde descomprimir los datos.
;; BC = tamaño de los datos a comprimir.
;; Salida
;; AF,DE desconocido
;; HL = HL+longitud de los datos descomprimidos
;; DE = DE+BC
;; 26 + 62 = 88
//-------------
org 16384
RLE_descompress
RLE_dec_loop
LD A,[HL] ; Leemos 1 byte
CP A,192
JR NC,RLE_dec ; si byte > 192 = está comprimido
test_end LDI ; Copiamos 1 byte en crudo
RET PO ; Volvemos si hemos terminado
JR RLE_dec_loop ; Repetimos el bucle
RLE_dec ; bucle para descompresión RLE
INC HL ; Nos colocamos en el valor
AND A,#3F
JR Z,test_end ; Si 192, es dato en crudo
PUSH BC
LD B,A ; B= numero de repeticiones
LD A,[HL]
bucle LD [DE],A ; \
INC DE ; Bucle de escritura B veces
DJNZ bucle ; /
POP BC
DEC BC ; Ajustamos el contador al usar RLE
JR test_end ; Copiamos 1 byte mas
//---------------
RLE_Comprimir
byte_1 LD E,[IX+#00] ; leer byte
INC IX ; incrementar posicion
DEC BC ; descontar contador
LD A,E ;
byte_2 CP A,#C0 ; Si es un codigo RLE
JR NC,RLE_compress ; tratar como RLE
CALL get_byte ; tomar el 2º byte
JR Z,ultimo_byte ; falta escribir el ultimo byte
CP A,E ;
JR Z,RLE_compress2 ; usar compresion RLE si son identicos
LD [HL],E ; son distintos, escribir el byte anterior
INC HL ;
LD E,A ; recuperar el ultimo byte leido
JR byte_2 ; continuar con la compresion
ultimo_byte LD [HL],E ; escribir el ultimo byte
INC HL ;
RET ; salir
RLE_compress2 LD D,#C1 ; eran identicos, empezar, con 2
JR RLE_Repetido
RLE_compress LD D,#C0 ; era un valor RLE original
RLE_Repetido CALL get_byte ; Obtener otro byte
JR Z,RLE_distinto ; Escribir el valor RLE si no hya mas bytes
CP A,E ; Comprobar si es identico
JR NZ,RLE_distinto ; Se encontro un byte distinto
INC D ; incrementar el contador de repeticiones
JR NZ,RLE_Repetido ; Otro byte identico
DEC D ; Se acabo el contador de repeticiones
RLE_distinto LD [HL],D ; \
INC HL ; \ escribir valor RLE
byte_simple LD [HL],E ; /
INC HL ; /
LD E,A ; Recuperar el ultimo byte distinto
JR byte_2 ; segir comprimiendo
get_byte LD A,B ; \
OR A,C ; Comprobar si es el ultimo byte
RET Z ; /
DEC BC ; descontar contador
LD A,[IX+#00] ; leer byte
INC IX ; incrementar posicion
RET ;
La rutina la probe con la rom, porque era lo que mas a mano tenia, esta en todos los emuladores, y es bastante aleatoria, como para por lo menos que el test diga, que el programa es fiable.
Una posible mejora es indicar cuantos bytes hay en crudo, no solo los comprimidos, con un byte extra, pudiendo ahorrar algunos bytes, si los datos son mayores o iguales que el #C0