aPLib, rutinas optimizadas

Programando el Amstrad en Ensamblador.
Reglas del Foro
Debido a que hay varios temas pidiendo ayuda para programar en ensamblador máquinas distintas al Amstrad CPC, con micro distinto al Z80 y que incluso dependen del sistema operativo, nos vemos en la necesidad de poner por escrito que estos posts son bienvenidos pero que no es el lugar adecuado ya que por estos lares nos dedicamos más al ensamblador del Z80, un microprocesador de 8 bits que tuvo su gran auge en ordenadores y consolas de los años 80.

De todas formas, esto no quita que alguien que sepa del asunto pueda postear alguna respuesta pero es más fácil encontrar foros dedicados a programar en ensamblador en Windows o MS-DOS que ayudarán más que nosotros:
http://www.lawebdelprogramador.com/news ... nsamblador
Avatar de Usuario
Metalbrain
Forero habitual
Forero habitual
Mensajes: 151
Registrado: Mar 30 Oct , 2007 1:45 pm
Ubicación: Sevilla

aPLib, rutinas optimizadas

Mensajepor Metalbrain » Dom 27 Ene , 2013 1:53 pm

Hace poco también estuve optimizando un poquito las rutinas de aPLib, otra buena alternativa para comprimir datos, así que ya va siendo hora de que las presente por aquí también. Como ventajas sobre exomizer:
- no necesita reservar memoria para una tabla temporal de 156 bytes.
- no añade una tabla de 26 bytes fijos al comienzo de los datos comprimidos, por lo que tiene más posibilidades de comprimir bloques pequeños de datos
- para bloques grandes, en muy raras ocasiones, comprime mejor (pero el 95% de las veces gana exomizer, que conste)
- más rápida (aunque ya no tanto tras las últimas optimizaciones de exomizer)

Podeis encontrar el programa compresor (appack.exe) aquí, junto con el descompresor original sin optimizar (muy muy lento):
http://www.smspower.org/maxim/uploads/S ... plib12.zip

Rutina optimizada en tamaño (156 bytes):

Código: Seleccionar todo

; aPPack decompressor
; original source by dwedit
; very slightly adapted by utopian
; optimized by Metalbrain

;hl = source
;de = dest

depack: ld ixl,128
apbranch1: ldi
aploop0: ld ixh,1 ;LWM = 0
aploop: call ap_getbit
jr nc,apbranch1
call ap_getbit2
jr nc,apbranch2
ld bc,16
call ap_getbit2
jr nc,apbranch3
apget4bits: call ap_getbit2
rl c
jr nc,apget4bits
ld a,b
jr z,apwritebyte
and a
ex de,hl ;write a previous byte (1-15 away from dest)
sbc hl,bc
ld a,(hl)
add hl,bc
ex de,hl
apwritebyte: ld (de),a ;write a 0
inc de
jr aploop0
apbranch3: ld c,(hl) ;use 7 bit offset, length = 2 or 3
rr c
ret z ;if a zero is found here, it's EOF
inc hl
ld a,b
adc a,2
push hl
push bc
pop iy
ld h,d
ld l,e
sbc hl,bc
ld c,a
jr ap_finishup2
apbranch2: call ap_getgamma ;use a gamma code * 256 for offset, another gamma code for length
dec c
ld a,c
sub ixh
jr z,ap_r0_gamma ;if gamma code is 2, use old r0 offset,
dec a
;do I even need this code?
;bc=bc*256+(hl), lazy 16bit way
ld b,a
ld c,(hl)
inc hl
push bc
pop iy

push bc

call ap_getgamma

ex (sp),hl ;bc = len, hl=offs
push de
ex de,hl

ld a,4
cp d
jr nc,apskip2
inc bc
or a
apskip2: ld hl,127
sbc hl,de
jr c,apskip3
inc bc
inc bc
apskip3: pop hl ;bc = len, de = offs, hl=junk
push hl
or a
ap_finishup: sbc hl,de
pop de ;hl=dest-offs, bc=len, de = dest
ap_finishup2: ldir
pop hl
ld ixh,b
jr aploop

ap_r0_gamma: call ap_getgamma ;and a new gamma code for length
push hl
push de
ex de,hl

push iy
pop de
jr ap_finishup

ap_getbit: ld a,ixl
ap_getbit2: add a,a
jr nz,ap_endbit
ld a,(hl)
inc hl
rla
ap_endbit: ld ixl,a
ret

ap_getgamma: ld bc,1
ap_getgammaloop:call ap_getbit
rl c
rl b
call ap_getbit2
jr c,ap_getgammaloop
ret
Rutina optimizada en velocidad (197 bytes):

Código: Seleccionar todo

; aPPack decompressor
; original source by dwedit
; very slightly adapted by utopian
; optimized by Metalbrain

;hl = source
;de = dest

depack: ld a,128
apbranch1: ldi
aploop2: ld ixh,1
aploop: add a,a
jr nz,apnogetbit1
ld a,(hl)
inc hl
rla
apnogetbit1: jr nc,apbranch1
add a,a
jr nz,apnogetbit2
ld a,(hl)
inc hl
rla
apnogetbit2: jr nc,apbranch2
add a,a
jr nz,apnogetbit3
ld a,(hl)
inc hl
rla
apnogetbit3: jr nc,apbranch3
ld bc,16 ;get an offset
apget4bits: add a,a
jr nz,apnogetbit4
ld a,(hl)
inc hl
rla
apnogetbit4: rl c
jr nc,apget4bits
jr nz,apbranch4
ex de,hl
ld (hl),b ;write a 0
ex de,hl
inc de
jp aploop2
apbranch4: ex af,af'
ex de,hl ;write a previous byte (1-15 away from dest)
sbc hl,bc
ld a,(hl)
add hl,bc
ld (hl),a
ex af,af'
ex de,hl
inc de
jp aploop2

apbranch3: ld c,(hl) ;use 7 bit offset, length = 2 or 3
inc hl
ex af,af'
rr c
ret z ;if a zero is found here, it's EOF
ld a,2
ld b,0
adc a,b
push hl
ld iyh,b
ld iyl,c
ld h,d
ld l,e
sbc hl,bc
ld c,a
ex af,af'
ldir
pop hl
ld ixh,b
jp aploop
apbranch2: call ap_getgamma ;use a gamma code * 256 for offset, another gamma code for length
dec c
ex af,af'
ld a,c
sub ixh
jr z,ap_r0_gamma
dec a

;do I even need this code?
;bc=bc*256+(hl), lazy 16bit way
ld b,a
ld c,(hl)
inc hl
ld iyh,b
ld iyl,c

push bc

call ap_getgamma2

ex (sp),hl ;bc = len, hl=offs
push de
ex de,hl

ex af,af'
ld a,4
cp d
jr nc,apskip2
inc bc
or a
apskip2: ld hl,127
sbc hl,de
jr c,apskip3
inc bc
inc bc
apskip3: pop hl ;bc = len, de = offs, hl=junk
push hl
or a
sbc hl,de
ex af,af'
pop de ;hl=dest-offs, bc=len, de = dest
ldir
pop hl
ld ixh,b
jp aploop

ap_r0_gamma: call ap_getgamma2 ;and a new gamma code for length
push hl
push de
ex de,hl

ld d,iyh
ld e,iyl
sbc hl,de
pop de ;hl=dest-offs, bc=len, de = dest
ldir
pop hl
ld ixh,b
jp aploop

ap_getgamma2: ex af,af'
ap_getgamma: ld bc,1
ap_getgammaloop:add a,a
jr nz,apnogetbit5
ld a,(hl)
inc hl
rla
apnogetbit5: rl c
rl b
add a,a
jr nz,apnogetbit6
ld a,(hl)
inc hl
rla
apnogetbit6: jr c,ap_getgammaloop
ret
Se puede aumentar la velocidad más todavía, expandiendo la rutina ap_getgamma de forma que pongamos inline los primeros pasos de la rutina, al precio de 15 bytes por cada bit optimizado (hasta el octavo, luego 17 hasta el 15 que sería el último). Aquí pongo un ejemplo con 2 bits optimizados (227 bytes):

Código: Seleccionar todo

; aPPack decompressor
; original source by dwedit
; very slightly adapted by utopian
; optimized by Metalbrain

;hl = source
;de = dest

depack: ld a,128
apbranch1: ldi
aploop2: ld ixh,1
aploop: add a,a
jr nz,apnogetbit1
ld a,(hl)
inc hl
rla
apnogetbit1: jr nc,apbranch1
add a,a
jr nz,apnogetbit2
ld a,(hl)
inc hl
rla
apnogetbit2: jr nc,apbranch2
add a,a
jr nz,apnogetbit3
ld a,(hl)
inc hl
rla
apnogetbit3: jr nc,apbranch3
ld bc,16 ;get an offset
apget4bits: add a,a
jr nz,apnogetbit4
ld a,(hl)
inc hl
rla
apnogetbit4: rl c
jr nc,apget4bits
jr nz,apbranch4
ex de,hl
ld (hl),b ;write a 0
ex de,hl
inc de
jp aploop2
apbranch4: ex af,af'
ex de,hl ;write a previous byte (1-15 away from dest)
sbc hl,bc
ld a,(hl)
add hl,bc
ld (hl),a
ex af,af'
ex de,hl
inc de
jp aploop2

apbranch3: ld c,(hl) ;use 7 bit offset, length = 2 or 3
inc hl
ex af,af'
rr c
ret z ;if a zero is found here, it's EOF
ld a,2
ld b,0
adc a,b
push hl
ld iyh,b
ld iyl,c
ld h,d
ld l,e
sbc hl,bc
ld c,a
ex af,af'
ldir
pop hl
ld ixh,b
jp aploop
apbranch2: call ap_getgamma ;use a gamma code * 256 for offset, another gamma code for length
dec c
ex af,af'
ld a,c
sub ixh
jr z,ap_r0_gamma
dec a

;do I even need this code?
;bc=bc*256+(hl), lazy 16bit way
ld b,a
ld c,(hl)
inc hl
ld iyh,b
ld iyl,c

push bc

call ap_getgamma2

ex (sp),hl ;bc = len, hl=offs
push de
ex de,hl

ex af,af'
ld a,4
cp d
jr nc,apskip2
inc bc
or a
apskip2: ld hl,127
sbc hl,de
jr c,apskip3
inc bc
inc bc
apskip3: pop hl ;bc = len, de = offs, hl=junk
push hl
or a
sbc hl,de
ex af,af'
pop de ;hl=dest-offs, bc=len, de = dest
ldir
pop hl
ld ixh,b
jp aploop

ap_r0_gamma: call ap_getgamma2 ;and a new gamma code for length
push hl
push de
ex de,hl

ld d,iyh
ld e,iyl
sbc hl,de
pop de ;hl=dest-offs, bc=len, de = dest
ldir
pop hl
ld ixh,b
jp aploop

ap_getgamma2: ex af,af'
ap_getgamma: ld bc,1
add a,a
jr nz,apnogetbit5
ld a,(hl)
inc hl
rla
apnogetbit5: rl c
add a,a
jr nz,apnogetbit6
ld a,(hl)
inc hl
rla
apnogetbit6: ret nc
add a,a
jr nz,apnogetbit7
ld a,(hl)
inc hl
rla
apnogetbit7: rl c
add a,a
jr nz,apnogetbit8
ld a,(hl)
inc hl
rla
apnogetbit8: ret nc
ap_getgammaloop:add a,a
jr nz,apnogetbit9
ld a,(hl)
inc hl
rla
apnogetbit9: rl c
rl b
add a,a
jr nz,apnogetbit10
ld a,(hl)
inc hl
rla
apnogetbit10: jr c,ap_getgammaloop
ret
Y por último una idea de Antonio Villena, gastando todavía más bytes, para favorecer el caso más común (247 bytes, 2 bits optimizados como en la anterior):

Código: Seleccionar todo

; aPPack decompressor
; original source by dwedit
; very slightly adapted by utopian
; optimized by Metalbrain & Antonio Villena

;hl = source
;de = dest

depack: ld a,128
apbranch1: ldi
aploop2: ld ixh,1
aploop: add a,a
jr nz,apnogetbit1
ld a,(hl)
inc hl
rla
apnogetbit1: jr nc,apbranch1
add a,a
jr nz,apnogetbit2
ld a,(hl)
inc hl
rla
apnogetbit2: jr nc,apbranch2
add a,a
jr nz,apnogetbit3
ld a,(hl)
inc hl
rla
apnogetbit3: jr nc,apbranch3
ld bc,16 ;get an offset
apget4bits: add a,a
jr nz,apnogetbit4
ld a,(hl)
inc hl
rla
apnogetbit4: rl c
jr nc,apget4bits
jr nz,apbranch4
ex de,hl
ld (hl),b ;write a 0
ex de,hl
inc de
jp aploop2
apbranch4: ex af,af'
ex de,hl ;write a previous byte (1-15 away from dest)
sbc hl,bc
ld a,(hl)
add hl,bc
ld (hl),a
ex af,af'
ex de,hl
inc de
jp aploop2

apbranch3: ld c,(hl) ;use 7 bit offset, length = 2 or 3
inc hl
ex af,af'
rr c
ret z ;if a zero is found here, it's EOF
ld a,2
ld b,0
adc a,b
push hl
ld iyh,b
ld iyl,c
ld h,d
ld l,e
sbc hl,bc
ld c,a
ex af,af'
ldir
pop hl
ld ixh,b
jp aploop
apbranch2: call ap_getgamma ;use a gamma code * 256 for offset, another gamma code for length
dec c
ex af,af'
ld a,c
sub ixh
jr z,ap_r0_gamma
dec a

;do I even need this code?
;bc=bc*256+(hl), lazy 16bit way
ld b,a
ld c,(hl)
inc hl
ld iyh,b
ld iyl,c

push bc

call ap_getgamma2

ex (sp),hl ;bc = len, hl=offs
push de
ex de,hl

ex af,af'
ld a,4
cp d
jr nc,apskip2
inc bc
or a
apskip2: ld hl,127
sbc hl,de
jr c,apskip3
inc bc
inc bc
apskip3: pop hl ;bc = len, de = offs, hl=junk
push hl
or a
sbc hl,de
ex af,af'
pop de ;hl=dest-offs, bc=len, de = dest
ldir
pop hl
ld ixh,b
jp aploop

ap_r0_gamma: call ap_getgamma2 ;and a new gamma code for length
push hl
push de
ex de,hl

ld d,iyh
ld e,iyl
sbc hl,de
pop de ;hl=dest-offs, bc=len, de = dest
ldir
pop hl
ld ixh,b
jp aploop

ap5: ld a,(hl)
inc hl
rla
jp apnogetbit5
ap6: ld a, (hl)
inc hl
rla
jp apnogetbit6
ap7: ld a, (hl)
inc hl
rla
jp apnogetbit7
ap8: ld a, (hl)
inc hl
rla
jp apnogetbit8
ap9: ld a, (hl)
inc hl
rla
jp apnogetbit9


ap10: ld a, (hl)
inc hl
rla
ret nc
jp ap_getgammaloop


ap_getgamma2: ex af, af'
ap_getgamma: ld bc, 1
add a, a
jr z, ap5
apnogetbit5: rl c
add a, a
jr z, ap6
apnogetbit6: ret nc
add a, a
jr z, ap7
apnogetbit7: rl c
add a, a
jr z, ap8
apnogetbit8: ret nc
ap_getgammaloop:add a, a
jr z, ap9
apnogetbit9: rl c
rl b
add a, a
jr z, ap10
apnogetbit10: ret nc
jp ap_getgammaloop

antoniovillena
Forero habitual
Forero habitual
Mensajes: 115
Registrado: Mar 26 Abr , 2011 9:25 pm

Re: aPLib, rutinas optimizadas

Mensajepor antoniovillena » Mié 09 May , 2018 12:18 pm

Buenas. Ha salido un compresor open source compatible con el descompresor de Aplib que mejora el ratio de compresión del mismo. Su autor es Sven-Åke Dahl y el código fuente está aquí:

https://github.com/svendahl/cap

Adjunto ejecutables para windows
Adjuntos
apc.zip
(24.86 KiB) Descargado 99 veces

Avatar de Usuario
Artaburu
Trasteador
Trasteador
Mensajes: 8419
Registrado: Vie 07 Oct , 2005 6:18 pm
Ubicación: En tu pantalla

Re: aPLib, rutinas optimizadas

Mensajepor Artaburu » Mié 09 May , 2018 12:56 pm

Gracias. Lo pruebo esta tarde a ver qué tal va. ¿Sabéis si hay y alguna comparativa vs exomizer?
Salu2,
Arta

antoniovillena
Forero habitual
Forero habitual
Mensajes: 115
Registrado: Mar 26 Abr , 2011 9:25 pm

Re: aPLib, rutinas optimizadas

Mensajepor antoniovillena » Mié 09 May , 2018 1:27 pm

Gracias. Lo pruebo esta tarde a ver qué tal va. ¿Sabéis si hay y alguna comparativa vs exomizer?
En este readme.txt hay una comparativa.

https://github.com/antoniovillena/zx7b

Sigue comprimiendo peor que exomizer


¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro


La Comunidad Española
ESP Soft, juegos para tu CPC Foro de Amstrad CPC Todos los juegos para CPC en un CD Web dedicada al Amstrad CPC (utilidades) Información útil para el CPC (talleres) Selección de juegos de Amstrad CPC Mundo CPC Pree Play then any Key CPC Basic