cursos:ensamblador:compresion_rle

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
cursos:ensamblador:compresion_rle [12-01-2024 15:23] sromerocursos:ensamblador:compresion_rle [19-01-2024 12:35] (actual) – [Programa de ejemplo de descompresión] sromero
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<length; i++)+  for (i=0; i<length; i++)
   {   {
      b1 = *src++;      b1 = *src++;
-     if( b1 > 192 )                    // byte comprimido?+     if (b1 > 192)                     // byte comprimido?
      {      {
         b2 = *src++;         b2 = *src++;
         i++;         i++;
-        for( j=0; j<(b1 & 63); j++ )   // sí, descomprime y escribe+        for (j=0; j<(b1 & 63); j++) {    // sí, descomprime y escribe
             *dst++ = b2;             *dst++ = b2;
 +        } 
      }      }
-     else+     else {
         *dst++ = b1;                   // no, es un byte de dato (escribe)         *dst++ = b1;                   // no, es un byte de dato (escribe)
 +     }  
   }   }
 } }
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                    ; leemos un byte
  
-    CP 192 +    cp 192 
-    JP NCRLE_dec_compressed          ; si byte > 192 = está comprimido +    jp ncrle_dec_compressed     ; si byte > 192 = está comprimido 
-    LD (DE), A                         ; si no está comprimido, escribirlo +    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 ab 
-    OR C +    or c 
-    JR NZRLE_dec_loop +    jr nzrle_dec_loop 
-    RET                                 ; miramos si hemos acabado+    ret                           ; miramos si hemos acabado
  
-RLE_dec_compressed                   ; bucle para descompresión +rle_dec_compressed              ; bucle para descompresión 
-    PUSH BC +    push bc 
-    AND 63                              ; cogemos el numero de repeticiones +    and %00111111                 ; cogemos el numero de repeticiones 
-    LD BA                             ; lo salvamos en B +    ld ba                       ; lo salvamos en B 
-    INC HL                              ; y leemos otro byte (dato a repetir) +    inc hl                        ; y leemos otro byte (dato a repetir) 
-    LD A, (HL)+    ld a, (hl)
  
-RLE_dec_loop3+rle_dec_loop3
-    LD (DE),A                           ; bucle de escritura del dato B veces +    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                              ; recuperamos BC +    pop bc                        ; recuperamos BC 
-    DEC BC                              ; Este DEC BC puede hacer BC=0 si los datos +    dec bc                        ; Este dec bc puede hacer BC=0 si los datos 
-                                        ; RLE no correctos. Cuidado (mem-smashing). +                                  ; RLE no son correctos. Cuidado (mem-smashing). 
-    DEC BC +    dec bc 
-    JR RLE_dec_loop2 +    jr rle_dec_loop2 
-    RET+    ret
 </code> </code>
  
Línea 565: Línea 567:
  
 \\  \\ 
-  * **Método INCBIN**: Incluyendo el binario directamente en PASMO con la directiva ''INCBIN'' asociándole una etiqueta para poder hacer referencia a él:\\ <code>+  * **Método INCBIN**: Incluyendo el binario directamente en Pasmo con la directiva ''INCBIN'' asociándole una etiqueta para poder hacer referencia a él:\\ \\ <code>
 Datos_Comprimidos: Datos_Comprimidos:
    INCBIN "fichero.rle"    INCBIN "fichero.rle"
Línea 571: Línea 573:
 \\  \\ 
  
-  * **Método BIN2CODE**: Convirtiendo los datos binarios a "texto" con una utilidad como BIN2C o BIN2CODE (las tenéis disponibles como descargas en la sección de ficheros). Estas utilidades para PC (Linux, MAC, DOS/Windows) toman un fichero binario y lo convierten a datos listos para incluir en nuestros programas:\\ <code>+  * **Método BIN2CODE**: Convirtiendo los datos binarios a "texto" con una utilidad como BIN2C o BIN2CODE (las tenéis disponibles como descargas en la sección de ficheros). Estas utilidades para PC (Linux, MAC, DOS/Windows) toman un fichero binario y lo convierten a datos listos para incluir en nuestros programas:\\ \\ <code>
 [sromero@compiler:~rlezx]$ bin2code sokoban.rle datos.asm a [sromero@compiler:~rlezx]$ bin2code sokoban.rle datos.asm a
 BIN2CODE v1.0             By NoP of Compiler SoftWare BIN2CODE v1.0             By NoP of Compiler SoftWare
Línea 579: Línea 581:
  
 [sromero@compiler:~rlezx]$ cat datos.asm [sromero@compiler:~rlezx]$ cat datos.asm
-;  File created with  BIN2CODE  v1.0  by  NOP of Compiler SoftWare+;  File created with  BIN2CODE  v1.0  by  nop of Compiler SoftWare
  
 BINDATASIZE   EQU   2571 BINDATASIZE   EQU   2571
Línea 606: Línea 608:
 ; 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+    ORG 35000
  
     ; Cargamos los datos y preparamos nuestra rutina     ; Cargamos los datos y preparamos nuestra rutina
-    LD HL, Pantalla_Comprimida +    ld hl, Pantalla_Comprimida 
-    LD DE, 16384 +    ld de, 16384 
-    LD BC, 2571 +    ld bc, 2571 
-    CALL RLE_decompress+    call RLE_decompress
  
 Wait_For_Keys_Pressed:         ; Bucle para esperar pulsación de tecla Wait_For_Keys_Pressed:         ; Bucle para esperar pulsación de tecla
-    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+    ret                          ; Fin del programa
  
-;+Aquí incluiremos el código de la rutina RLE_decompress 
-;; RLE_decompress +;; --- 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          si byte > 192 = está comprimido +
-    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 +
-    RET                                 ; miramos si hemos acabado +
- +
-RLE_dec_compressed:                    ; bucle para descompresión +
-    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),                          ; bucle de escritura del dato B veces +
-    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í 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:
-  INCBIN sokoban.rle+    INCBIN sokoban.rle
  
-END 35000+    END 35000
 </code> </code>
  
Línea 690: Línea 648:
 ===== 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,  en los foros oficiales de Speccy.org,  nos aporta una modificación de nuestra rutina original y una rutina compresora nativa:
  
 \\  \\ 
-//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 ''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).//
 \\  \\ 
  
Línea 706: Línea 664:
 ;; BC = tamaño de los datos a comprimir. ;; BC = tamaño de los datos a comprimir.
 ;; Salida ;; Salida
-;; AF,DE   desconocido+;; AF, DE   desconocido
 ;; HL = HL+longitud de los datos comprimidos ;; HL = HL+longitud de los datos comprimidos
 ;; IX = IX+BC ;; IX = IX+BC
Línea 715: Línea 673:
 ;; BC = tamaño de los datos a comprimir. ;; BC = tamaño de los datos a comprimir.
 ;; Salida ;; Salida
-;; AF,DE   desconocido+;; AF, DE   desconocido
 ;; HL = HL+longitud de los datos descomprimidos ;; HL = HL+longitud de los datos descomprimidos
 ;; DE = DE+BC ;; DE = DE+BC
Línea 721: Línea 679:
 //------------- //-------------
  
-RLE_descompress +RLE_descompress: 
-RLE_dec_loop +rle_dec_loop: 
-          LD   A,[HL]             ; Leemos 1 byte +          ld a(hl)                     ; Leemos 1 byte 
-          CP   A,192 +          cp a, 192 
-          JR   NC,RLE_dec         ; si byte > 192 = está comprimido +          jr ncrle_dec                 ; si byte > 192 = está comprimido 
-test_end  LDI                     ; Copiamos 1 byte en crudo +rle_test_end: 
-          RET   PO                ; Volvemos si hemos terminado +          ldi                            ; Copiamos 1 byte en crudo 
-          JR   RLE_dec_loop       ; Repetimos el bucle +          ret pO                         ; Volvemos si hemos terminado 
-RLE_dec                           ; bucle para descompresión RLE +          jr rle_dec_loop                ; Repetimos el bucle 
-          INC   HL                ; Nos colocamos en el valor +rle_dec:                                 ; bucle para descompresión RLE 
-          AND   A,#3F +          inc hl                         ; Nos colocamos en el valor 
-          JR   Z,test_end         ; Si 192, es dato en crudo +          and a$3f 
-          PUSH   BC +          jr zrle_test_end             ; Si 192,  es dato en crudo 
-          LD   B,A                ; B= numero de repeticiones +          push bc 
-          LD   A,[HL] +          ld ba                        ; B= numero de repeticiones 
-bucle     LD   [DE],A             ; \ +          ld a(hl) 
-          INC   DE                ;  Bucle de escritura B veces +rle_bucle: 
-          DJNZ   bucle            ; / +          ld (de)a                     ; \ 
-          POP   BC +          inc de                         ;  Bucle de escritura B veces 
-          DEC   BC                ; Ajustamos el contador al usar RLE +          djnz rle_bucle                 ; / 
-          JR   test_end           ; Copiamos 1 byte mas+          pop bc 
 +          dec bc                         ; Ajustamos el contador al usar RLE 
 +          jr rle_test_end                ; Copiamos 1 byte mas
  
  
 //--------------- //---------------
-RLE_Comprimir +RLE_Comprimir: 
-byte_1 +rle_byte_1: 
-          LD   E,[IX+#00]         ; leer byte +          ld e(ix+$00)                 ; leer byte 
-          INC   IX                ; incrementar posicion +          inc ix                         ; incrementar posicion 
-          DEC   BC                ; descontar contador +          dec bc                         ; descontar contador 
-          LD   A,E                ; +          ld ae 
-byte_2 +rle_byte_2: 
-          CP   A,#C0              ; Si es un codigo RLE +          cp a, #C0                      ; Si es un codigo RLE 
-          JR   NC,RLE_compress    ;  tratar como RLE +          jr ncrle_compress            ;  tratar como RLE 
-          CALL   get_byte         ; tomar el 2º byte +          call rle_get_byte              ; tomar el 2º byte 
-          JR   Z,ultimo_byte      ; falta escribir el ultimo byte +          jr zrle_ultimo_byte          ; falta escribir el ultimo byte 
-          CP   A,E                ; +          cp a, E 
-          JR   Z,RLE_compress2    ; usar compresion RLE si son identicos +          jr zrle_compress2            ; usar compresion RLE si son identicos 
-          LD   [HL],E             ; son distintos, escribir el byte anterior +          ld (hl)e                     ; son distintos,  escribir el byte anterior 
-          INC   HL                ; +          inc hl 
-          LD   E,A                ; recuperar el ultimo byte leido +          ld ea                        ; recuperar el ultimo byte leido 
-          JR   byte_2             ; continuar con la compresion +          jr byte_2                      ; continuar con la compresion 
-ultimo_byte   LD   [HL],E         ; escribir el ultimo byte +rle_ultimo_byte: 
-          INC   HL                ; +          ld (hl)e                     ; escribir el ultimo byte 
-          RET         ; salir +          inc hl 
-RLE_compress2 +          ret                            ; salir 
-          LD   D,#C1              ; eran identicos, empezar, con 2 +rle_compress2: 
-          JR   RLE_Repetido +          ld d$c1                      ; eran identicos,  empezar,  con 2 
-RLE_compress +          jr rle_repetido 
-          LD   D,#C0              ; era un valor RLE original +rle_compress: 
-RLE_Repetido +          ld d$c0                      ; era un valor RLE original 
-          CALL   get_byte         ; Obtener otro byte +rle_repetido: 
-          JR   Z,RLE_distinto     ; Escribir el valor RLE si no hya mas bytes +          call get_byte                  ; Obtener otro byte 
-          CP   A,E                ; Comprobar si es identico +          jr zrle_distinto             ; Escribir el valor RLE si no hya mas bytes 
-          JR   NZ,RLE_distinto    ; Se encontro un byte distinto +          cp a, E                        ; Comprobar si es identico 
-          INC                   ; incrementar el contador de repeticiones +          jr nzrle_distinto            ; Se encontro un byte distinto 
-          JR   NZ,RLE_Repetido    ; Otro byte identico +          inc d                          ; incrementar el contador de repeticiones 
-          DEC                   ; Se acabo el contador de repeticiones +          jr nzrle_repetido            ; Otro byte identico 
-RLE_distinto +          dec d                          ; Se acabo el contador de repeticiones 
-          LD   [HL],D             ; \ +rle_distinto: 
-          INC   HL                ;  \  +          ld (hl)d                     ; \ 
-byte_simple                       ;   / escribir valor RLE +          inc l                          ;  \  
-          LD   [HL],E             ;  / +rle_byte_simple:                         ;   / escribir valor RLE 
-          INC   HL                ; / +          ld (hl)e                     ;  / 
-          LD   E,A                ; Recuperar el ultimo byte distinto +          inc hl                         ; / 
-          JR   byte_2             ; seguir comprimiendo +          ld ea                        ; Recuperar el ultimo byte distinto 
-get_byte +          jr rle_byte_2                      ; seguir comprimiendo 
-          LD   A,B                ; \ +rle_get_byte: 
-          OR   A,C                ;  Comprobar si es el ultimo byte +          ld ab                        ; \ 
-          RET                   ; / +          or a, C                        ;  Comprobar si es el ultimo byte 
-          DEC   BC                ; descontar contador +          ret z                          ; / 
-          LD   A,[IX+#00]         ; leer byte +          dec bc                         ; descontar contador 
-          INC   IX                ; incrementar posicion +          ld a(ix+$00)                 ; leer byte 
-          RET+          inc ix                         ; incrementar posicion 
 +          ret
 </code> </code>
  
Línea 844: Línea 805:
  
 <code z80> <code z80>
-    LD    HL, scr_datos_zx0    ; origen = datos comprimidos +    ld    hl, scr_datos_zx0    ; origen = datos comprimidos 
-    LD    DE, 16384            ; destino = pantalla +    ld    de, 16384            ; destino = pantalla 
-    CALL  decompress_zx0+    call  decompress_zx0
 </code> </code>
  
Línea 861: Línea 822:
  
 <code z80> <code z80>
-ORG 33500+    ORG 33500
  
-    LD HL, pantalla_comprimida   ; datos comprimidos +    ld hl, pantalla_comprimida   ; datos comprimidos 
-    LD DE, 16384                 ; destino compresion +    ld de, 16384                 ; destino compresion 
-    CALL dzx0_standard           ; descomprimir+    call dzx0_standard           ; descomprimir
  
 loop: loop:
-    JR loop                      ; bucle para no volver a BASIC+    jr loop                      ; bucle para no volver a BASIC
  
     INCLUDE "dzx0_standard.asm"     INCLUDE "dzx0_standard.asm"
Línea 875: Línea 836:
     INCBIN "pantalla.scr.zx0"     INCBIN "pantalla.scr.zx0"
  
-END 33500+    END 33500
 </code> </code>
  
Línea 906: Línea 867:
  
 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.
- 
- 
  
 \\  \\ 
Línea 921: Línea 880:
   * [[https://github.com/einar-saukas/ZX0|ZX0]] : Repositorio del compresor/descompresor ZX0.   * [[https://github.com/einar-saukas/ZX0|ZX0]] : Repositorio del compresor/descompresor ZX0.
   * {{:cursos:ensamblador:zx0_test.zip|Ficheros de prueba del descompresor ZX0 (con Sokoban.scr)}}.   * {{:cursos:ensamblador:zx0_test.zip|Ficheros de prueba del descompresor ZX0 (con Sokoban.scr)}}.
- 
  
 \\  \\ 
Línea 927: Línea 885:
  
  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.
- 
  
 \\  \\ 
 **[ [[.:indice|⬉]] | [[.:gfx5_mapeados|⬅]] | [[.:avanzadas1|➡]] ]** **[ [[.:indice|⬉]] | [[.:gfx5_mapeados|⬅]] | [[.:avanzadas1|➡]] ]**
 +
  • cursos/ensamblador/compresion_rle.1705073002.txt.gz
  • Última modificación: 12-01-2024 15:23
  • por sromero