Karoshi MSX Community
05 de Julio de 2021, 07:32:30 pm *
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.

Ingresar con nombre de usuario, contraseña y duración de la sesión
Noticias:
 
   Inicio   Ayuda Buscar Ingresar Registrarse  
Páginas: [1] 2
  Imprimir  
Autor Tema: ¿Es posible que sea mas rápido escribir RLE que RAW en VRAM?  (Leído 9366 veces)
0 Usuarios y 1 Visitante están viendo este tema.
Iggy Rock
Visitante
« : 21 de Enero de 2012, 12:34:52 pm »

Esto viene de la idea que surgió en este hilo

La cuestión es que es mas rápido escribir una serie de datos iguales usando OUT(n),A en vez de series de OUTI's sin tener en cuenta limitaciones de escritura en VRAM. Esto es un hecho, ahora bien,  el manejo de los datos comprimidos o codificados es lo que hará que este sea una método viable o al menos si hay un límite aceptable desde el cual es preferible usar datos RLE.

EL programa que adjunto incluye un bitmap en sc3 que se comprime internamente de esta manera tan poco óptima:

En cada par de bytes:

Byte1: Dato literal
Byte2: nº de repeticiones hasta 128

De esta manera el gráfico se comprime un 55% aproximadamente. Queda en un 45% del tamaño original.

y lo vuelco a la VRAM de esta manera tan poco elegante y por supuesto tampoco optimizada:

Código:
RLEDATA_OUT: LD HL,IMAGE_RLE

LD A,[HL]
INC HL
PUSH HL
LD L,[HL]
LD H,$43
JP [HL]
.ORG $4300

REPT 128
OUT [$98],A
ENDR

POP HL
INC HL
LD A,[HL]
AND A
RET Z
INC HL
PUSH HL
LD L,[HL]
LD H,$43
JP [HL]


frente a:

Código:
RAWDATA:

CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
El resultado se puede ver pulsando la barra espaciadora o dejándola pulsada.  Gana RAWDATA!

¿que os parece optimizar el código de manera que sea "rentable" su uso?



 




En línea
Iggy Rock
Visitante
« Respuesta #1 : 21 de Enero de 2012, 12:42:39 pm »

Por cierto, sin tocar nada del código RLEDATA_OUT e incluyendo dos NOP's por cada OUTI, la ventaja es para el primero. Ademas hay que tener en cuenta el menor espacio ocupado. Son dos ventajas! Grin

El dato $00 indica fin del archivo.
« Última modificación: 21 de Enero de 2012, 02:00:39 pm por Iggy Rock » En línea
Iggy Rock
Visitante
« Respuesta #2 : 21 de Enero de 2012, 01:46:46 pm »

Bueno, algo mejor cambiando el orden de los datos por cada par de bytes. (nº rep, dato literal):

Código:
RLEDATA_OUT: LD DE,IMAGE_RLE

LD A,[DE]
LD L,A
INC DE
LD A,[DE]
INC DE
LD H,$43
JP [HL]
.ORG $4300

REPT 128
OUT [$98],A
ENDR

LD A,[DE]
CP 129
RET Z
LD L,A
INC DE
LD A,[DE]
INC DE
JP [HL]
En línea
aorante
Karoshi Maniac
****
Mensajes: 451


nuTella Power!


WWW Email
« Respuesta #3 : 21 de Enero de 2012, 01:51:16 pm »

La segunda ROM parece que no funciona bien... Muestra gráficos extraños en vez del avatar de un conocido coder Cheesy

por otro lado,
¿que hace "JP [HL]"?
he visto que también esta con los registros de indice.

y "REPT 128", ¿que es?  Huh

No acabo de entender lo que hace RLEDATA_OUT. Puedes poner algún comentario?
Justamente estoy interesado en una rutina descompresora RLE a VRAM y sobre todo aprender  Cheesy

Estoy haciendo una app(win) para tratar gráficos de SC2/4 (creo que puse un comentario en estos foros) y quiero añadirle la opción de comprimir en RLE.

saludos!

En línea

--------------------------------- ------ ----- --- -- -
aorante/303bcn
http://aorante.blogspot.com
http://twitter.com/#!/aorante
http://303bcn.wordpress.com/
--------------------------------- ------ ----- --- -- -
Iggy Rock
Visitante
« Respuesta #4 : 21 de Enero de 2012, 02:00:15 pm »

Ese @aorante!: No tengas en cuenta la Segunda ROM.

- JP (HL) salta a la dirección indicada por el registro HL. Es un poco confuso al ir entre paréntesis.
- REPT X/ ENDR ... Eduardo te vacastigar: " REPITELO CIEN VECES"  Grin. Repite X veces lo que hay entre las dos sentencias.
- Las rutinas de compresión y descompresión son muy rudimentarias, solo para pruebas. Pero si te interesa te la pasaré una vez esté optimizada.

En línea
aorante
Karoshi Maniac
****
Mensajes: 451


nuTella Power!


WWW Email
« Respuesta #5 : 21 de Enero de 2012, 02:22:02 pm »

Ese @aorante!: No tengas en cuenta la Segunda ROM.
Ok. Ya he visto la tercera!  Smiley

Citar
- JP (HL) salta a la dirección indicada por el registro HL. Es un poco confuso al ir entre paréntesis.

entiendo, pero al "leer" el codigo es un lio!   Shocked
Se me han suicidado 128 neuronas!!!  Grin

Citar
- REPT X/ ENDR ... Eduardo te vacastigar: " REPITELO CIEN VECES"  Grin. Repite X veces lo que hay entre las dos sentencias.

es que pico rutinas en el SDCC (combino C y ASM), y no tiene tantas facilities como el asMSX...   Tongue

Citar
- Las rutinas de compresión y descompresión son muy rudimentarias, solo para pruebas. Pero si te interesa te la pasaré una vez esté optimizada.

Muchas gracias...  Cheesy
En línea

--------------------------------- ------ ----- --- -- -
aorante/303bcn
http://aorante.blogspot.com
http://twitter.com/#!/aorante
http://303bcn.wordpress.com/
--------------------------------- ------ ----- --- -- -
Iggy Rock
Visitante
« Respuesta #6 : 21 de Enero de 2012, 05:16:17 pm »

Un poquito mas rápido usando la pila:

Código:
RLEDATA_OUT: LD [STACK],SP
LD SP,IMAGE_RLE
POP BC

LD A,C
LD L,B
LD H,$43
JP [HL]
.ORG $4300

REPT 128
OUT [$98],A
ENDR

POP BC
LD A,C
LD L,B
AND A
JP Z,RLEDATA_END
JP [HL]
RLEDATA_END: LD SP,[STACK]
RET
En línea
Mortimer
Karoshi Lover
***
Mensajes: 216


WWW
« Respuesta #7 : 21 de Enero de 2012, 07:15:50 pm »

Muy interesante, veo que mi intuición iba por buen camino  Cheesy

Y ya para rizar el rizo, si queremos también la máxima compresión y hay espacio en la ram, quizás se pueda aplicar antes alguna compresión basada en Lempel-Ziv, porque los datos RLE a su vez suelen ser bastantes comprimibles con ese sistema.

En línea
Iggy Rock
Visitante
« Respuesta #8 : 21 de Enero de 2012, 07:45:33 pm »

Muy interesante, veo que mi intuición iba por buen camino  Cheesy

Y ya para rizar el rizo, si queremos también la máxima compresión y hay espacio en la ram, quizás se pueda aplicar antes alguna compresión basada en Lempel-Ziv, porque los datos RLE a su vez suelen ser bastantes comprimibles con ese sistema.



Si que es muy interesante! Cheesy. Con la última optimización usando la pila, por lo que he visto una compresión del 50% aprox. compensa en espacio y en velocidad. Depende de como estén ordenados los datos puede ser incluso mas rápido que OUTI a secas y por supuesto mas rápido si es OUTI+NOP.

La compresión es muy sencilla para permitir la velocidad en la descompresión a VRAM pero si hay grandes areas continuas puede ser bastante efectivo.

Os dejo el código por si quieres trastear o aorante quiere mirarlo para su uso:

* Hay que añadir un bitmap en screen 3 (&H0600 bytes)

Código:
.page 1
.ROM
.start BOOT
.DB "RLE2VDP"


VRAMFRM EQU $0000
DATA_PORT EQU $0098 ;PUEDE VARIARSE
REG_PORT EQU $0099 ;PUEDE VARIARSE
IMAGE_RLE EQU $8800
STACK EQU $87F0
INTVECTAB EQU $FC00 ;TABLA -$101
HOOK EQU $FDFD

.INCLUDE "ASM/SYSVAR.ASM"
.INCLUDE "ASM/KEYBOARD.ASM"



BOOT: EI

CALL $0075

DI


;COMPRESION RLE 127

LD HL,IMAGE1
LD DE,IMAGE_RLE
COMPRLEBC1: LD BC,$0000
LD A,[HL]
AND A
JR Z,COMPRLEND
COMPRLEBC0: INC HL ;CPI PARA OPTIMIZAR
LD C,[HL]
BIT 7,B
JR Z,COMPRLEJP3
LD B,0
DEC HL
JR COMPRLEJP2

COMPRLEJP3: INC B

CP C
JR Z,COMPRLEBC0
COMPRLEJP2: LD [DE],A ;GUARDA DATO
INC DE
LD A,B
RLCA ;DUPLICA
NEG ;NEGATIVO

LD [DE],A ;GUARDA Nº REPETICIONES EN NEGATIVO
INC DE
JR COMPRLEBC1
COMPRLEND: LD [DE],A

LD HL,RAWDATA


;CONFIGURA GANCHO INTERRUPCIONES IM2

LD HL,RLEDATA
LD [HOOK+1],HL
CALL INSTALLISR
I_LOOP: JR I_LOOP

INSTALLISR: DI
LD HL,INTVECTAB
LD E,L
LD D,H
INC DE
LD [HL],HOOK>>8
LD BC,256
LDIR
LD A,$C3
LD [HOOK],A

LD A,INTVECTAB>>8
LD I,A
IM 2
EI
RET   

;________________________________________________

RLEDATA: IN A,[REG_PORT]
LD A,44
LD B,7
CALL W_REGVDP
LD HL,VRAMFRM
CALL INIVPOKE
CALL RLEDATA_OUT
LD A,11
LD B,7
CALL W_REGVDP

;BARRA ESPACIADORA
;OUT: FLAG C

LD C,8
CALL K_GET_LINE
RRA
JR NC,NO_SPACE1

LD HL,RAWDATA
LD      [HOOK+1],HL
                LD      A,$C3
        LD      [HOOK],A

NO_SPACE1: EI
RETI


RLEDATA_OUT: LD [STACK],SP
LD SP,IMAGE_RLE
POP BC

LD A,C
LD L,B
LD H,$44
JP [HL]
.ORG $4400

REPT 128
OUT [DATA_PORT],A
ENDR

POP BC
LD L,B
LD A,C
AND A
JP Z,RLEDATA_END
JP [HL]

RLEDATA_END: LD SP,[STACK]
RET


RAWDATA: IN A,[REG_PORT]

LD A,44
LD B,7
CALL W_REGVDP

LD HL,VRAMFRM
CALL INIVPOKE

LD HL,IMAGE1
LD C,DATA_PORT

CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S
CALL REPOUTI256 ;256 OTIR'S

LD A,11
LD B,7
CALL W_REGVDP

;BARRA ESPACIADORA
;OUT: FLAG C

LD C,8
CALL K_GET_LINE
RRA
JR NC,NO_SPACE2

LD HL,RLEDATA
LD      [HOOK+1],HL
                LD      A,$C3
        LD      [HOOK],A

NO_SPACE2: EI
RETI
REPOUTI256:

REPT 256
OUTI
ENDR
RET

W_REGVDP:       OUT     (REG_PORT),A
                LD      A,B
                OR      10000000B
                OUT     (REG_PORT),A
                RET

INIVPOKE:       LD      A,L
                OUT     [REG_PORT],A
                LD      A,H
                OR      01000000B
                OUT     [REG_PORT],A
                RET

IMAGE1: .INCBIN "IMAGE1.SC3"
IMAGE1_OEF: DB 0
En línea
Dioniso
Visitante
« Respuesta #9 : 21 de Enero de 2012, 08:49:11 pm »

Yo me quedo con el vuelco "raw".

Si se volcaran 128 veces el valor 1 y 128 veces el valor 0 pues sería un buen método el que planteáis, pero si cada vez que no se repite el valor hay que hacer esto:

Código:
POP HL
INC HL
LD A,[HL]
AND A
RET Z
INC HL
PUSH HL
LD L,[HL]
LD H,$43
JP [HL]

pues olvidaos ... Tendría que ser una imagen de lo más simple para que medio funcionara.

La diferencia entre OUT y OUTI es de 5 t-states, nada más.

POP   HL      ; 10 t-states
INC   HL      ;  6 t-states
LD   A,[HL]      ;  7 t-states
AND   A      ;  4 t-states
RET   Z      ; 11 t-states
INC   HL      ;  6 t-states
PUSH   HL      ; 11 t-states
LD   L,[HL]      ;  7 t-states
LD   H,$43      ;  7 t-states
JP   [HL]      ;  4 t-states

-Esto hace un total de 73 t-states.
-Le añadimos un OUT, es decir, 11 t-states.
-Son 11 instrucciones por lo que se le habría que añadir 11 t-states más en modo IM1.
-Total, 95 s-tates para un valor cada vez que no se repite.

RLE = 95 t-states, RAW = 17 (mediante OUTI). Supongo que la imagen debería tener una compresión de casi el 80% para que el método RLE a VRAM fuera mejor que el volcado RAW.
« Última modificación: 21 de Enero de 2012, 08:54:51 pm por Dioniso » En línea
Dioniso
Visitante
« Respuesta #10 : 21 de Enero de 2012, 08:56:23 pm »

He visto que también lo haríais en modo IM2. Bueno, en ese caso se recortan la rutinas:

RLE = 84 frente a RAW = 16
En línea
Dioniso
Visitante
« Respuesta #11 : 21 de Enero de 2012, 09:06:36 pm »

Por qué no me habré leído el post entero ...

Acabo de ver que habéis optimizado la rutina. Ahora sería:

POP   BC      ; 10 t-states
LD   L,B      ;  4 t-states         
LD   A,C      ;  4 t-states         
AND   A      ;  4 t-states         
JP   Z,RLEDATA_END   ; 10 t-states      
JP   [HL]      ;  4 t-states
más el OUT

Lo que en modo IM2 resulta en lo siguiente:

RLE = 47, RAW = 16  cuando no se repite el valor
RLE = 11, RAW = 16 cuando se repite el valor

edito: corregida la gamba del modo IM2 más abajo
« Última modificación: 21 de Enero de 2012, 09:28:51 pm por Dioniso » En línea
Mortimer
Karoshi Lover
***
Mensajes: 216


WWW
« Respuesta #12 : 21 de Enero de 2012, 09:11:16 pm »

He visto que también lo haríais en modo IM2. Bueno, en ese caso se recortan la rutinas:

RLE = 84 frente a RAW = 16

Creo que estás mezclando el modo de interrupción (IM0, IM1 ó IM2) con la velocidad de ejecución debido al ciclo adicional del estado M1 del Z80. Independientemente del modo de interrupción, los retardos introducidos son (Según http://map.grauw.nl/resources/z80instr.php)

Citar
Every instruction has 1 additional M1 wait state
Instructions starting with a CB, DD, ED, FD, DDCB or DDFD opcode have two additional M1 wait states

Por lo que la direrencia entre OUT (n),A y OUTI son 6 ciclos.

En cuanto al problema de la sobrecarga si hay pocos datos repetidos, y si queremos complicarnos mucho la vida, podríamos utilizar un bit del byte que indica las repeticiones, para indicar si lo siguiente que viene es un bloque que no merece la pena ser comprimido y volcar con OUTI, o es RLE. En desensamblado añadiría algo de sobrecarga, pero la rutina de compresión ya tendría que ser algo más inteligente para que valorara cuando indicar que lo siguiente es una cadena literal
« Última modificación: 21 de Enero de 2012, 09:17:58 pm por Mortimer » En línea
Dioniso
Visitante
« Respuesta #13 : 21 de Enero de 2012, 09:23:03 pm »

Creo que estás mezclando el modo de interrupción (IM0, IM1 ó IM2) con la velocidad de ejecución debido al ciclo adicional del estado M1 del Z80.

Ha sido una paja mental mía. Sí ... La edad.  angel

RLE = 54, RAW = 18  cuando no se repite el valor
RLE = 12, RAW = 18 cuando se repite el valor


Vaya gamba con el IM2 ...
« Última modificación: 21 de Enero de 2012, 09:41:20 pm por Dioniso » En línea
Iggy Rock
Visitante
« Respuesta #14 : 21 de Enero de 2012, 09:27:27 pm »

@Dioniso , gracias por echarle un tiento al código. Cheesy

Si, la última optimización mejora bastante los tiempos y permite un mayor rango de archivos candidatos a RLE.
En línea
Páginas: [1] 2
  Imprimir  
 
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.21 | SMF © 2013, Simple Machines XHTML 1.0 válido! CSS válido!