Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
cursos:ensamblador:compresion_rle [06-01-2024 16:45] – [Ejemplo completo] sromero | cursos:ensamblador:compresion_rle [19-01-2024 12:35] (actual) – [Programa de ejemplo de descompresión] sromero | ||
---|---|---|---|
Línea 12: | Línea 12: | ||
En resumen: | En resumen: | ||
- | \\ | + | |
- | \\ | + | \\ |
* Proceso de **compresión**: | * Proceso de **compresión**: | ||
- | \\ | + | \\ |
* Proceso de **descompresión**: | * Proceso de **descompresión**: | ||
- | \\ | + | \\ |
Los procesos de COMPRESION y DESCOMPRESION son funciones que reciben como entrada los datos en crudo o los datos comprimidos (respectivamente) y producen como salida los datos comprimidos o los datos originales. | Los procesos de COMPRESION y DESCOMPRESION son funciones que reciben como entrada los datos en crudo o los datos comprimidos (respectivamente) y producen como salida los datos comprimidos o los datos originales. | ||
Línea 26: | Línea 26: | ||
- | \\ | + | \\ |
===== Fundamentos de la compresión RLE ===== | ===== Fundamentos de la compresión RLE ===== | ||
Línea 59: | Línea 59: | ||
</ | </ | ||
- | \\ | + | \\ |
- | \\ | + | \\ |
Ahora bien ... ¿qué tipo de marcador podemos utilizar? | Ahora bien ... ¿qué tipo de marcador podemos utilizar? | ||
- | \\ | + | \\ |
En el algoritmo RLE **se utilizan como marcadores de repetición los 2 bits superiores del dato**. Estos bits, el número 7 y el número 6, tienen el siguiente valor: | En el algoritmo RLE **se utilizan como marcadores de repetición los 2 bits superiores del dato**. Estos bits, el número 7 y el número 6, tienen el siguiente valor: | ||
Línea 131: | Línea 131: | ||
</ | </ | ||
- | \\ | + | \\ |
* 1 -> (<192) = No está comprimido\\ -> El 1 lo copio en Descomprimido. | * 1 -> (<192) = No está comprimido\\ -> El 1 lo copio en Descomprimido. | ||
Línea 151: | Línea 151: | ||
* 6 -> (<192) = No está comprimido\\ -> El 6 lo copio en Descomprimido. | * 6 -> (<192) = No está comprimido\\ -> El 6 lo copio en Descomprimido. | ||
- | \\ | + | \\ |
| | ||
Línea 160: | Línea 160: | ||
| | ||
- | \\ | + | \\ |
===== Los datos que son mayores de 191 ===== | ===== Los datos que son mayores de 191 ===== | ||
Línea 203: | Línea 203: | ||
- | \\ | + | \\ |
===== Resumen sobre la compresión ===== | ===== Resumen sobre la compresión ===== | ||
Línea 209: | Línea 209: | ||
Antes de ver el pseudocódigo y las rutinas descompresoras y compresoras, | Antes de ver el pseudocódigo y las rutinas descompresoras y compresoras, | ||
- | \\ | + | \\ |
* La **compresión** es un proceso que convierte una serie de datos de tamaño N en otra serie de datos de tamaño M (siendo M menor que N), mediante un determinado algoritmo de procesado de los datos originales. | * La **compresión** es un proceso que convierte una serie de datos de tamaño N en otra serie de datos de tamaño M (siendo M menor que N), mediante un determinado algoritmo de procesado de los datos originales. | ||
Línea 225: | Línea 225: | ||
* La **descompresión RLE** es un algoritmo de descompresión que, a partir de unos datos comprimidos con RLE, obtiene los datos originales mediante la " | * La **descompresión RLE** es un algoritmo de descompresión que, a partir de unos datos comprimidos con RLE, obtiene los datos originales mediante la " | ||
- | \\ | + | \\ |
- | \\ | + | \\ |
===== Cómo trabajaremos con la compresión ===== | ===== Cómo trabajaremos con la compresión ===== | ||
A continuación vamos a ver el pseudocódigo y funciones ensamblador y C de descompresión RLE y compresión RLE. Pero antes, es importante destacar la forma en que usaremos estas funciones: | A continuación vamos a ver el pseudocódigo y funciones ensamblador y C de descompresión RLE y compresión RLE. Pero antes, es importante destacar la forma en que usaremos estas funciones: | ||
- | \\ | + | \\ |
- | \\ | + | \\ |
* **Compresión**: | * **Compresión**: | ||
Línea 239: | Línea 239: | ||
* **Descompresión de los datos**: La descompresión de los datos la realizamos en nuestro programa de Spectrum, mediante una rutina programada en ensamblador de Z80 o C para Z88DK. La rutina es pequeña y rápida, por lo que nos permitirá desempaquetar nuestra pantalla de 3102 bytes directamente sobre la VideoRAM (por ejemplo). Los 3102 bytes de nuestra pantalla de ejemplo, expandidos, serán los 6912 bytes originales del SCR inicial. Se dice pues que la rutina de descompresión trabaja //al vuelo// o //en tiempo real//. | * **Descompresión de los datos**: La descompresión de los datos la realizamos en nuestro programa de Spectrum, mediante una rutina programada en ensamblador de Z80 o C para Z88DK. La rutina es pequeña y rápida, por lo que nos permitirá desempaquetar nuestra pantalla de 3102 bytes directamente sobre la VideoRAM (por ejemplo). Los 3102 bytes de nuestra pantalla de ejemplo, expandidos, serán los 6912 bytes originales del SCR inicial. Se dice pues que la rutina de descompresión trabaja //al vuelo// o //en tiempo real//. | ||
- | \\ | + | \\ |
===== Rutina descompresora ===== | ===== Rutina descompresora ===== | ||
La rutina descompresora de RLE debe recibir como parámetros los siguientes valores: | La rutina descompresora de RLE debe recibir como parámetros los siguientes valores: | ||
- | \\ | + | \\ |
- | \\ | + | \\ |
* Los datos comprimidos con RLE a descomprimir: | * Los datos comprimidos con RLE a descomprimir: | ||
* El tamaño de los datos comprimidos (necesario para el bucle de descompresión). | * El tamaño de los datos comprimidos (necesario para el bucle de descompresión). | ||
* Un puntero o dirección de memoria apuntando a dónde queremos descomprimir los datos. | * Un puntero o dirección de memoria apuntando a dónde queremos descomprimir los datos. | ||
- | \\ | + | \\ |
La rutina deberá ir cogiendo cada byte del bloque de datos comprimido y decidir si es un dato "sin comprimir" | La rutina deberá ir cogiendo cada byte del bloque de datos comprimido y decidir si es un dato "sin comprimir" | ||
Línea 298: | Línea 298: | ||
<code c> | <code c> | ||
// | // | ||
- | void RLE_decompress_C( unsigned char *src, unsigned char *dst, int length ) | + | void RLE_decompress_C(unsigned char *src, unsigned char *dst, int length) |
{ | { | ||
int i; | int i; | ||
unsigned char b1, b2, j; | unsigned char b1, b2, j; | ||
- | for( i=0; i< | + | for (i=0; i< |
{ | { | ||
b1 = *src++; | b1 = *src++; | ||
- | if( b1 > 192 ) // byte comprimido? | + | if (b1 > 192) |
{ | { | ||
b2 = *src++; | b2 = *src++; | ||
i++; | i++; | ||
- | for( j=0; j<(b1 & 63); j++ ) | + | for (j=0; j<(b1 & 63); j++) { |
*dst++ = b2; | *dst++ = b2; | ||
+ | } | ||
} | } | ||
- | else | + | |
*dst++ = b1; // no, es un byte de dato (escribe) | *dst++ = b1; // no, es un byte de dato (escribe) | ||
+ | | ||
} | } | ||
} | } | ||
Línea 320: | Línea 322: | ||
| | ||
- | \\ | + | \\ |
* Usamos los punteros src y dst para leer y escribir en memoria (operador de indirección ** * **). | * Usamos los punteros src y dst para leer y escribir en memoria (operador de indirección ** * **). | ||
Línea 327: | Línea 329: | ||
* Si está comprimido, no es un dato a guardar sino un dato RLE. Obtenemos el número de repeticiones reales (b1 en el ejemplo) y leemos el siguiente dato desde src. Ese dato (b2) tiene que ser escrito b1 veces. | * Si está comprimido, no es un dato a guardar sino un dato RLE. Obtenemos el número de repeticiones reales (b1 en el ejemplo) y leemos el siguiente dato desde src. Ese dato (b2) tiene que ser escrito b1 veces. | ||
- | \\ | + | \\ |
Ahora trasladamos esa rutina a ensamblador de Z80, y nos queda lo siguiente: | Ahora trasladamos esa rutina a ensamblador de Z80, y nos queda lo siguiente: | ||
Línea 343: | Línea 345: | ||
RLE_decompress: | RLE_decompress: | ||
- | RLE_dec_loop: | + | rle_dec_loop: |
- | LD A,(HL) ; leemos un byte | + | ld a, (hl) |
- | | + | cp 192 |
- | JP NC, RLE_dec_compressed | + | jp nc, rle_dec_compressed |
- | LD (DE), A ; si no está comprimido, escribirlo | + | |
- | INC DE | + | inc de |
- | INC HL | + | inc hl |
- | DEC BC | + | dec bc |
- | RLE_dec_loop2: | + | rle_dec_loop2: |
- | LD A,B | + | ld a, b |
- | OR C | + | or c |
- | JR NZ, RLE_dec_loop | + | jr nz, rle_dec_loop |
- | RET ; miramos si hemos acabado | + | |
- | RLE_dec_compressed: ; bucle para descompresión | + | rle_dec_compressed: |
- | PUSH BC | + | push bc |
- | AND 63 | + | and %00111111 |
- | LD B, A ; lo salvamos en B | + | ld b, a ; lo salvamos en B |
- | INC HL | + | inc hl |
- | LD A, (HL) | + | ld a, (hl) |
- | RLE_dec_loop3: | + | rle_dec_loop3: |
- | LD (DE),A ; bucle de escritura del dato B veces | + | |
- | INC DE | + | inc de |
- | DJNZ RLE_dec_loop3 | + | djnz rle_dec_loop3 |
- | INC HL | + | inc hl |
- | POP BC | + | pop bc |
- | DEC BC | + | dec bc |
- | | + | ; RLE no son correctos. Cuidado (mem-smashing). |
- | DEC BC | + | dec bc |
- | JR RLE_dec_loop2 | + | jr rle_dec_loop2 |
- | RET | + | ret |
</ | </ | ||
- | | + | \\ |
- | + | ||
- | <code c> | + | |
- | int RLE_decompress_ASM( unsigned char *, unsigned char *, int ); | + | |
- | + | ||
- | + | ||
- | // | + | |
- | // RLE_decompress_ASM( src, dst, longitud ); | + | |
- | // | + | |
- | int RLE_decompress_ASM( unsigned char *src, unsigned char *dst, int length ) | + | |
- | { | + | |
- | + | ||
- | #asm | + | |
- | ld hl,2 | + | |
- | add hl,sp | + | |
- | + | ||
- | ld c, (hl) | + | |
- | inc hl | + | |
- | ld b, (hl) | + | |
- | inc hl // BC = lenght | + | |
- | + | ||
- | ld e, (hl) | + | |
- | inc hl | + | |
- | ld d, (hl) | + | |
- | inc hl // de = dst | + | |
- | push de | + | |
- | + | ||
- | ld e, (hl) | + | |
- | inc hl | + | |
- | ld d, (hl) | + | |
- | inc hl // de = src | + | |
- | + | ||
- | ex de, hl | + | |
- | pop de // now de = dst and hl = src | + | |
- | + | ||
- | // After this: HL = source, DE = destination, | + | |
- | + | ||
- | .RLE_dec_loop | + | |
- | ld a, | + | |
- | + | ||
- | cp 192 | + | |
- | jp nc, RLE_dec_compressed | + | |
- | ld (de), a // si no está comprimido, escribirlo | + | |
- | inc de | + | |
- | inc hl | + | |
- | dec bc | + | |
- | + | ||
- | .RLE_dec_loop2 | + | |
- | ld a,b | + | |
- | or c | + | |
- | jr nz, RLE_dec_loop | + | |
- | | + | |
- | + | ||
- | .RLE_dec_compressed | + | |
- | push bc | + | |
- | and 63 // cogemos el numero de repeticiones | + | |
- | ld b, a // lo salvamos en B | + | |
- | inc hl // y leemos otro byte (dato a repetir) | + | |
- | ld a, (hl) | + | |
- | + | ||
- | .RLE_dec_loop3 | + | |
- | ld (de), | + | |
- | inc de | + | |
- | djnz RLE_dec_loop3 | + | |
- | inc hl | + | |
- | pop bc // recuperamos BC | + | |
- | dec bc // Este DEC BC puede hacer BC=0 si los datos | + | |
- | // RLE no correctos. Cuidado (mem-smashing). | + | |
- | dec bc | + | |
- | jr RLE_dec_loop2 | + | |
- | ret | + | |
- | + | ||
- | #endasm | + | |
- | + | ||
- | } | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | \\ | + | |
===== Rutina compresora ===== | ===== Rutina compresora ===== | ||
Línea 525: | Línea 449: | ||
char scanline_width, | char scanline_width, | ||
{ | { | ||
- | | + | |
- | unsigned int bytecounter, | + | unsigned int bytecounter, |
- | unsigned char b1, b2, data; | + | unsigned char b1, b2, data; |
- | | + | |
- | bytecounter = 1; | + | bytecounter = 1; |
- | width = 0; | + | width = 0; |
- | | + | |
- | | + | |
- | { | + | { |
- | | + | b2 = src[offset++]; |
- | | + | width++; |
- | while ((b2 == b1) && | + | |
- | (bytecounter < scanline_width-1 ) && | + | (bytecounter < scanline_width-1 ) && |
- | (width < scanline_width-1)) | + | (width < scanline_width-1)) |
- | { | + | |
- | | + | |
- | b2 = src[offset++]; | + | |
- | | + | |
- | } | + | |
- | if (width >= scanline_width) | + | |
- | { | + | |
- | offset += scanline_width-width; | + | |
- | width = 0; | + | |
- | } | + | |
- | if (bytecounter != 1) | + | |
- | { | + | |
- | data = RLE_LIMIT+bytecounter; | + | |
- | dst[dst_pointer++] = data; | + | |
- | dst[dst_pointer++] = b1; | + | |
- | } | + | |
- | + | ||
- | if (bytecounter == 1) | + | |
- | { | + | |
- | if (b1 < RLE_LIMIT) | + | |
{ | { | ||
- | dst[dst_pointer++] = b1; | + | bytecounter++; |
+ | b2 = src[offset++]; | ||
+ | width++; | ||
} | } | ||
- | | + | |
{ | { | ||
- | | + | offset += scanline_width-width; |
- | dst[dst_pointer++] = data; | + | width = 0; |
- | dst[dst_pointer++] = b1; | + | } |
+ | if (bytecounter != 1) | ||
+ | { | ||
+ | | ||
+ | dst[dst_pointer++] = data; | ||
+ | dst[dst_pointer++] = b1; | ||
} | } | ||
- | } | ||
- | bytecounter = 1; | + | if (bytecounter == 1) |
- | | + | { |
- | } | + | if (b1 < RLE_LIMIT) |
- | while (offset <= length); | + | { |
+ | dst[dst_pointer++] = b1; | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | data = RLE_LIMIT+1; | ||
+ | dst[dst_pointer++] = data; | ||
+ | dst[dst_pointer++] = b1; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | | ||
+ | b1 = b2; | ||
+ | } | ||
+ | while (offset <= length); | ||
- | | + | |
} | } | ||
</ | </ | ||
Línea 588: | Línea 512: | ||
Lo normal durante el desarrollo del juego será " | Lo normal durante el desarrollo del juego será " | ||
- | En la sección de //Ficheros y Enlaces// tenéis disponible el compresor y descompresor | + | En la sección de //Ficheros y Enlaces// tenéis disponible el compresor y descompresor |
- | \\ | + | \\ |
===== Ejemplo completo ===== | ===== Ejemplo completo ===== | ||
Línea 604: | Línea 528: | ||
//Pantalla de carga del Sokoban// | //Pantalla de carga del Sokoban// | ||
;#; | ;#; | ||
- | \\ | + | \\ |
| | ||
- | \\ | + | \\ |
==== Compresión de la imagen ==== | ==== Compresión de la imagen ==== | ||
Línea 636: | Línea 560: | ||
Como vemos, el tamaño de la pantalla ha pasado de 6912 bytes a 2571, lo que supone un ratio de compresión del 63%. La imagen ha ocupado finalmente casi 1/3 del tamaño original. Un ahorro de este tipo puede suponer gran cantidad de espacio aprovechable a partir de las pantallas de presentación, | Como vemos, el tamaño de la pantalla ha pasado de 6912 bytes a 2571, lo que supone un ratio de compresión del 63%. La imagen ha ocupado finalmente casi 1/3 del tamaño original. Un ahorro de este tipo puede suponer gran cantidad de espacio aprovechable a partir de las pantallas de presentación, | ||
- | \\ | + | \\ |
==== Inclusión de la imagen en nuestro programa ==== | ==== Inclusión de la imagen en nuestro programa ==== | ||
Línea 642: | Línea 566: | ||
Ahora que ya tenemos el fichero binario de datos RLE comprimidos (sokoban.rle), | Ahora que ya tenemos el fichero binario de datos RLE comprimidos (sokoban.rle), | ||
- | \\ | + | \\ |
- | * **Método INCBIN**: Incluyendo el binario directamente en PASMO con la directiva | + | * **Método INCBIN**: Incluyendo el binario directamente en Pasmo con la directiva |
Datos_Comprimidos: | Datos_Comprimidos: | ||
| | ||
</ | </ | ||
- | \\ | + | \\ |
- | * **Método BIN2CODE**: Convirtiendo los datos binarios a " | + | * **Método BIN2CODE**: Convirtiendo los datos binarios a " |
[sromero@compiler: | [sromero@compiler: | ||
BIN2CODE v1.0 By NoP of Compiler SoftWare | BIN2CODE v1.0 By NoP of Compiler SoftWare | ||
Línea 657: | Línea 581: | ||
[sromero@compiler: | [sromero@compiler: | ||
- | ; File created with BIN2CODE | + | ; File created with BIN2CODE |
BINDATASIZE | BINDATASIZE | ||
BINDATA LABEL BYTE | BINDATA LABEL BYTE | ||
- | DB | + | |
- | | + | DB |
- | | + | DB |
- | | + | DB |
- | | + | DB |
- | | + | DB |
- | | + | (etc...) |
</ | </ | ||
- | Es decir: el método 1 hace que PASMO incluya el binario directamente dentro de nuestro programa, y el método 2 lo convierte a directivas de datos "DB" | + | Es decir: el método 1 hace que Pasmo incluya el binario directamente dentro de nuestro programa, y el método 2 lo convierte a directivas de datos '' |
- | \\ | + | \\ |
==== Programa de ejemplo de descompresión ==== | ==== Programa de ejemplo de descompresión ==== | ||
Línea 679: | Línea 603: | ||
| | ||
- | El programa siguiente, | + | El programa siguiente, |
<code asm> | <code asm> | ||
; Prueba de descompresion RLE | ; Prueba de descompresion RLE | ||
; Desempaquetamos un SCR comprimido con RLE sobre la pantalla | ; Desempaquetamos un SCR comprimido con RLE sobre la pantalla | ||
- | ORG 35000 | + | |
- | + | ||
- | ; Cargamos los datos y preparamos nuestra rutina | + | |
- | LD HL, Pantalla_Comprimida | + | |
- | LD DE, 16384 | + | |
- | LD BC, 2571 | + | |
- | CALL RLE_decompress | + | |
+ | ; Cargamos los datos y preparamos nuestra rutina | ||
+ | ld hl, Pantalla_Comprimida | ||
+ | ld de, 16384 | ||
+ | ld bc, 2571 | ||
+ | call RLE_decompress | ||
Wait_For_Keys_Pressed: | Wait_For_Keys_Pressed: | ||
- | XOR A | + | xor a |
- | IN A, (254) | + | in a, ($fe) |
- | OR 224 | + | or %11100000 |
- | INC A | + | inc a |
- | JR Z, Wait_For_Keys_Pressed | + | jr z, Wait_For_Keys_Pressed |
- | + | | |
- | RET ; Fin del programa | + | |
- | + | ||
- | + | ||
- | ;; | + | |
- | ;; RLE_decompress | + | |
- | ;; Descomprime un bloque de datos RLE de memoria a memoria. | + | |
- | ;; | + | |
- | ;; Entrada a la rutina: | + | |
- | ;; | + | |
- | ;; HL = dirección origen de los datos RLE. | + | |
- | ;; DE = destino donde descomprimir los datos. | + | |
- | ;; BC = tamaño de los datos comprimidos. | + | |
- | ;; | + | |
- | RLE_decompress: | + | |
- | + | ||
- | RLE_dec_loop: | + | |
- | LD A, (HL) ; leemos un byte | + | |
- | + | ||
- | CP 192 | + | |
- | JP NC, RLE_dec_compressed | + | |
- | LD (DE), A ; si no está comprimido, escribirlo | + | |
- | INC DE | + | |
- | INC HL | + | |
- | DEC BC | + | |
- | + | ||
- | RLE_dec_loop2: | + | |
- | LD A,B | + | |
- | OR C | + | |
- | JR NZ, RLE_dec_loop | + | |
- | | + | |
- | + | ||
- | RLE_dec_compressed: | + | |
- | PUSH BC | + | |
- | AND 63 ; cogemos el numero de repeticiones | + | |
- | LD B, A ; lo salvamos en B | + | |
- | INC HL ; y leemos otro byte (dato a repetir) | + | |
- | LD A, (HL) | + | |
- | + | ||
- | RLE_dec_loop3: | + | |
- | LD (DE), | + | |
- | INC DE | + | |
- | DJNZ RLE_dec_loop3 | + | |
- | INC HL | + | |
- | POP BC ; recuperamos BC | + | |
- | DEC BC ; Este DEC BC puede hacer BC=0 si los datos | + | |
- | ; RLE no correctos. Cuidado (mem-smashing). | + | |
- | DEC BC | + | |
- | JR RLE_dec_loop2 | + | |
- | RET | + | |
+ | ; Aquí incluiremos el código de la rutina RLE_decompress | ||
+ | ;; --- RLE_decompress --- | ||
; Aquí viene nuestra pantalla comprimida con RLE. | ; Aquí viene nuestra pantalla comprimida con RLE. | ||
; Hay que darse cuenta de que está fuera de todo | ; Hay que darse cuenta de que está fuera de todo | ||
- | ; código ejecutable, es decir, el RET de la rutina | + | ; código ejecutable, es decir, el ret de la rutina |
- | ; principal y el RET de las subrutina de RLE_Decompress | + | ; principal y el ret de las subrutina de RLE_Decompress |
; hacen que nunca se llegue a este punto para ejecución. | ; hacen que nunca se llegue a este punto para ejecución. | ||
Pantalla_Comprimida: | Pantalla_Comprimida: | ||
- | | + | |
- | END 35000 | + | |
</ | </ | ||
- | \\ | + | \\ |
- | | + | |
- | \\ | + | \\ |
===== Rutina optimizada por Z80user ===== | ===== Rutina optimizada por Z80user ===== | ||
- | El usuario Z80user, en los foros oficiales de Speccy.org, nos aporta una modificación de nuestra rutina original y una rutina compresora nativa: | + | El usuario Z80user, |
- | \\ | + | \\ |
- | //He leído el articulo del RLE, 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 descompresión y salen identicas. He utilizado 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 (compresora 62 bytes, descompresora 26 bytes).// | + | //He leído el articulo del RLE, 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 descompresión y salen identicas. He utilizado un pequeño truquito con el '' |
- | \\ | + | \\ |
<code asm> | <code asm> | ||
Línea 788: | Línea 664: | ||
;; BC = tamaño de los datos a comprimir. | ;; BC = tamaño de los datos a comprimir. | ||
;; Salida | ;; Salida | ||
- | ;; AF,DE | + | ;; AF, DE |
;; HL = HL+longitud de los datos comprimidos | ;; HL = HL+longitud de los datos comprimidos | ||
;; IX = IX+BC | ;; IX = IX+BC | ||
Línea 797: | Línea 673: | ||
;; BC = tamaño de los datos a comprimir. | ;; BC = tamaño de los datos a comprimir. | ||
;; Salida | ;; Salida | ||
- | ;; AF,DE | + | ;; AF, DE |
;; HL = HL+longitud de los datos descomprimidos | ;; HL = HL+longitud de los datos descomprimidos | ||
;; DE = DE+BC | ;; DE = DE+BC | ||
Línea 803: | Línea 679: | ||
// | // | ||
- | RLE_descompress | + | RLE_descompress: |
- | RLE_dec_loop | + | rle_dec_loop: |
- | | + | |
- | | + | |
- | | + | |
- | test_end | + | rle_test_end: |
- | | + | ldi |
- | | + | |
- | RLE_dec | + | |
- | | + | rle_dec: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | bucle | + | |
- | | + | rle_bucle: |
- | | + | ld (de), a ; \ |
- | | + | |
- | | + | |
- | | + | |
+ | | ||
+ | | ||
// | // | ||
- | RLE_Comprimir | + | RLE_Comprimir: |
- | byte_1 | + | rle_byte_1: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | byte_2 | + | rle_byte_2: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ultimo_byte | + | rle_ultimo_byte: |
- | | + | ld (hl), e ; escribir el ultimo byte |
- | | + | |
- | RLE_compress2 | + | |
- | | + | rle_compress2: |
- | | + | |
- | RLE_compress | + | |
- | | + | rle_compress: |
- | RLE_Repetido | + | |
- | | + | rle_repetido: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | RLE_distinto | + | |
- | | + | rle_distinto: |
- | | + | |
- | byte_simple | + | |
- | | + | rle_byte_simple: |
- | | + | |
- | | + | |
- | | + | |
- | get_byte | + | |
- | | + | rle_get_byte: |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
+ | | ||
</ | </ | ||
- | | ||
- | + | \\ | |
- | \\ | + | |
===== ZX0: el algoritmo de compresión definitivo ===== | ===== ZX0: el algoritmo de compresión definitivo ===== | ||
Línea 908: | Línea 785: | ||
Pasamos de 6912 bytes a sólo 1383 bytes, una reducción espectacular que nos produce un fichero sokoban.scr.zx0 listo para usar. | Pasamos de 6912 bytes a sólo 1383 bytes, una reducción espectacular que nos produce un fichero sokoban.scr.zx0 listo para usar. | ||
- | Este fichero puede ser incluído después en nuestro programa con INCBIN o introducido en un TAP para ser cargado como un bloque de datos con "LOAD "" | + | Este fichero puede ser incluído después en nuestro programa con INCBIN o introducido en un TAP para ser cargado como un bloque de datos con '' |
Después, en nuestro programa, sólo tenemos que utilizar una de las rutinas descompresoras disponibles para desempaquetar los datos comprimidos en la zona de memoria deseada. | Después, en nuestro programa, sólo tenemos que utilizar una de las rutinas descompresoras disponibles para desempaquetar los datos comprimidos en la zona de memoria deseada. | ||
Línea 928: | Línea 805: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 945: | Línea 822: | ||
<code z80> | <code z80> | ||
- | ORG 33500 | + | |
- | | + | |
- | | + | |
- | | + | |
loop: | loop: | ||
- | | + | |
INCLUDE " | INCLUDE " | ||
Línea 959: | Línea 836: | ||
INCBIN " | INCBIN " | ||
- | END 33500 | + | |
</ | </ | ||
Línea 974: | Línea 851: | ||
\\ | \\ | ||
- | También tenemos disponibles en la web de ZX0 rutinas que descomprimen al revés en memoria, denominadas dzx0_standard_back y dzx0_turbo_back. | + | También tenemos disponibles en la web de ZX0 rutinas que descomprimen al revés en memoria, denominadas |
La utilidad de las rutinas " | La utilidad de las rutinas " | ||
Línea 991: | Línea 868: | ||
A día de hoy, ZX0 es una herramienta imprescindible para hacer programas y juegos de Spectrum, ya que los ratios de compresión son muy buenos y el uso de datos comprimidos (gráficos, textos, e incluso código) supone una enorme diferencia en tiempos de carga y cantidad de recursos que podemos poner en nuestros juegos. | A día de hoy, ZX0 es una herramienta imprescindible para hacer programas y juegos de Spectrum, ya que los ratios de compresión son muy buenos y el uso de datos comprimidos (gráficos, textos, e incluso código) supone una enorme diferencia en tiempos de carga y cantidad de recursos que podemos poner en nuestros juegos. | ||
- | + | \\ | |
- | + | ||
- | \\ | + | |
===== Ficheros ===== | ===== Ficheros ===== | ||
Línea 1006: | Línea 881: | ||
* {{: | * {{: | ||
- | + | \\ | |
- | \\ | + | |
===== En resumen ===== | ===== En resumen ===== | ||
Hemos visto los fundamentos de la compresión y descompresión RLE, así como rutinas C y ASM para implementarlos en nuestros programas. Mediante lo visto en este capítulo, podemos obtener un gran ahorro de memoria en nuestros programas, pudiendo introducir más cantidad de gráficos en el mismo espacio. También permite que pueda caber más código, más sonido o más texto, ya que aunque no apliquemos la compresión sobre este tipo de datos, podremos aprovechar el espacio que dejen libre nuestros gráficos comprimidos. | Hemos visto los fundamentos de la compresión y descompresión RLE, así como rutinas C y ASM para implementarlos en nuestros programas. Mediante lo visto en este capítulo, podemos obtener un gran ahorro de memoria en nuestros programas, pudiendo introducir más cantidad de gráficos en el mismo espacio. También permite que pueda caber más código, más sonido o más texto, ya que aunque no apliquemos la compresión sobre este tipo de datos, podremos aprovechar el espacio que dejen libre nuestros gráficos comprimidos. | ||
- | |||
\\ | \\ | ||
**[ [[.: | **[ [[.: | ||
+ |