News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_roudoudou

Shrinkler Z80 decrunch routine

Started by roudoudou, 10:42, 31 January 18

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

roudoudou

great! I will update official sources tonight after testing!
My pronouns are RASM and ACE

Urusergi

-6 bytes
SHRINKLER_DECRUNCH:    ; Init range decoder state
            LD HL,&0C00+8+SHRINKLER_DR
            LD DE,&0C00+7+SHRINKLER_DR
            LD BC,&0C00
            LD (HL),C
            INC HL
            LD (HL),&80
            LDDR
            LD C,&08
            DEC HL
            LDDR
            INC (HL)
            PUSH IY
            POP DE

LIT:        SCF
            LD HL,SHRINKLER_D6


Also, we have to eliminate all sentences like that:
PUSH IY
POP DE

&

PUSH DE
POP IY


It's can be reduced one more byte if we use DE as destination:

SHRINKLER_DECRUNCH:    ; Init range decoder state
            PUSH DE
            LD HL,&0C00+8+SHRINKLER_DR
            LD DE,&0C00+7+SHRINKLER_DR
            LD BC,&0C00
            LD (HL),C
            INC HL
            LD (HL),&80
            LDDR
            LD C,&08
            DEC HL
            LDDR
            INC (HL)
            POP DE

LIT:        SCF
            LD HL,SHRINKLER_D6


roudoudou

thanks, i updated first post with 255 bytes (one call version) and 262 bytes (multiple calls version)


now, source=IX and destination=DE
My pronouns are RASM and ACE

antoniovillena


antoniovillena

Another -1




shrinkler_getkind:
        ;Use parity as context
        ld      l, 1
shrinkler_altgetbit:
        ld      a, l
        and     e
        ld      h, a
        dec     hl
        ld      (shrinkler_d6), hl





        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
        ; Reference
        call    shrinkler_altgetbit

antoniovillena

-3 bytes in onecall version if shrinkler_pr is even with this code:




shrinkler_decrunch:
        ; Init range decoder state
        ld      hl, shrinkler_pr
shrinkler_repeat:
        ld      a, l
        rrca
        and     $80
        ld      (hl), a
        inc     hl
        ld      a, h
        cp      (shrinkler_pr+$d00)>>8
        jr      nz, shrinkler_repeat

antoniovillena

same lenght without even condition:




shrinkler_decrunch:
        ; Init range decoder state
        ld      hl, shrinkler_pr
shrinkler_repeat:
        ld      (hl), 0
        inc     hl
        ld      (hl), $80
        inc     hl
        ld      a, h
        cp      (shrinkler_pr+$d00)>>8
        jr      nz, shrinkler_repeat

antoniovillena

-1 byte


shrinkler_decrunch:
        ; Init range decoder state
        ld      bc, shrinkler_pr
        xor     a
shrinkler_repeat:
        ld      (bc), a
        xor     $80
        inc     bc
        ld      h, ($f400-shrinkler_pr)>>8
        add     hl, bc
        jr      nc, shrinkler_repeat

antoniovillena

-2 bytes to the recall version:




shrinkler_decrunch:
        ; Init range decoder state
        ld      hl, shrinkler_dr
        xor     a
        ex      af, af'
        xor     a
        ld      bc, $070d
        ld      (hl), 1
shrinkler_repeat:
        inc     hl
        ex      af, af'
        ld      (hl), a
        djnz    shrinkler_repeat
        ld      a, $80
        dec     c
        jr      nz, shrinkler_repeat

roudoudou

 ;D  like it!


first post updated with 250 bytes onecall and 259 bytes recall versions
My pronouns are RASM and ACE

antoniovillena

Quote from: roudoudou on 09:29, 21 February 18
;D  like it!


first post updated with 250 bytes onecall and 259 bytes recall versions
You can change >>8 by /256 if problems with assemblers

Enviado desde mi MI 5C mediante Tapatalk


antoniovillena

-1 byte. Sorry, complete code


shrinkler_getnumber:
        ; Out: Number in HL
        ld      bc, 1
        ld      hl, shrinkler_d6+1
        ld      (hl), a
        dec     hl
        ld      (hl), b
shrinkler_numberloop:
        inc     (hl)
        inc     (hl)
        call    shrinkler_getbit
        jr      c, shrinkler_numberloop
        dec     (hl)
shrinkler_bitsloop:
        call    shrinkler_getbit
        rl      c
        rl      b
        dec     (hl)
        dec     (hl)
        ret     m
        jr      shrinkler_bitsloop


;--------------------------------------------------
        ; Out: Bit in C
shrinkler_readbit:
        pop     de
        ld      (shrinkler_d3), hl
        ld      hl, (shrinkler_d4)
        adc     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2)
        jr      nz, shrinkler_rb1
        adc     hl, hl
        jr      nz, shrinkler_rb2
        ; HL=DE=0
shrinkler_rb0:
        ccf
        ld      d, (ix)               ; DEHL=(a4) big endian value read!
        ld      e, (ix+1)
        ex      de, hl
        inc     ix
        inc     ix
        jr      nc, shrinkler_rb0
        adc     hl, hl
        ex      de, hl
shrinkler_rb1:
        adc     hl, hl
shrinkler_rb2:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; written in little endian
        ld      hl, (shrinkler_d2)
        adc     hl, hl
        ld      (shrinkler_d2), hl
        jr      shrinkler_getbit1


shrinkler_getkind:
        ;Use parity as context
        ld      l, 1
shrinkler_altgetbit:
        ld      a, l
        and     e
        ld      h, a
        dec     hl
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx


shrinkler_getbit1:
        ld      hl, (shrinkler_d3)
        push    hl
        add     hl, hl
        jr      nc, shrinkler_readbit
        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ld      b, d
        ld      c, e                    ; bc=de=d1 / hl=a1
        ld      a, $eb
shrinkler_shift4:
        srl     b
        rr      c
        add     a, a
        jr      c, shrinkler_shift4-1
        sbc     hl, bc                  ; hl=d1-d1/16
        ex      de, hl
        ld      b, (hl)
        ld      (hl), d
        dec     hl
        ld      c, (hl)
        ld      (hl), e
        ex      (sp), hl
        ex      de, hl
        sbc     hl, hl
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        sub     $b
        jr      nz, shrinkler_muluw
        pop     bc                      ; bc=d1 initial
        ld      hl, (shrinkler_d2)
        sbc     hl, de
        jr      nc, shrinkler_zero


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ld      a, (bc)
        sub     1
        ld      (bc), a
        inc     bc
        ld      a, (bc)
        sbc     a, $f0                  ; (a1)+#FFF
        ld      (bc), a
        ex      de, hl
        jr      shrinkler_d3ret


shrinkler_decrunch:
        ; Init range decoder state
        ld      hl, shrinkler_dr
        xor     a
        ex      af, af'
        xor     a
        ld      bc, $070d
        ld      (hl), 1
shrinkler_repeat:
        inc     hl
        ex      af, af'
        ld      (hl), a
        djnz    shrinkler_repeat
        ld      a, $80
        dec     c
        jr      nz, shrinkler_repeat


shrinkler_lit:
        scf
        ld      hl, shrinkler_d6
shrinkler_getlit:
        call    nc, shrinkler_getbit
        rl      (hl)
        jr      nc, shrinkler_getlit
        ldi
        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
        ; Reference
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, 0
        add     hl, de
        ldir
        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ld      hl, 2
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        ; oneprob*adjust < oneprob so carry is always cleared...
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

antoniovillena

Another -1


shrinkler_getnumber:
        ; Out: Number in BC
        ld      bc, 1
        ld      hl, shrinkler_d6+1
        ld      (hl), a
        dec     hl
        ld      (hl), c
shrinkler_numberloop:
        inc     (hl)
        call    shrinkler_getbit
        inc     (hl)
        jr      c, shrinkler_numberloop
shrinkler_bitsloop:
        dec     (hl)
        dec     (hl)
        ret     m
        call    shrinkler_getbit
        rl      c
        rl      b
        jr      shrinkler_bitsloop

antoniovillena

Another -1

shrinkler_readlength:
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, 0
        add     hl, de
        ldir
        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        dec     a
        call    shrinkler_getnumber




shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ld      a, 4
        ret

antoniovillena

#89
QuoteI am not sure 100% about it, but...


After some tests this doesn't work always, but maybe interesting (as comments) for extreme demo coders. So the final size is 248/256 bytes (and with this dirty trick 243/252).

roudoudou

Interresting, i'll try tonight (and i hope i will find test files which work and not!)
My pronouns are RASM and ACE

antoniovillena

-1 byte recall

shrinkler_readbit:
        pop     de
        ld      (shrinkler_d3), hl
        ld      hl, (shrinkler_d4)
        ld      de, (shrinkler_d4+2)
shrinkler_rb0:
        adc     hl, hl
        ld      (shrinkler_d4), hl
        ex      de, hl
        jr      nz, shrinkler_rb2
        adc     hl, hl
        jr      nz, shrinkler_rb3
        ; HL=DE=0
shrinkler_rb1:
        ccf
        ld      d, (ix)               ; DEHL=(a4) big endian value read!
        ld      e, (ix+1)
        ex      de, hl
        inc     ix
        inc     ix
        jr      nc, shrinkler_rb1
        jr      shrinkler_rb0
shrinkler_rb2:
        adc     hl, hl
shrinkler_rb3:
        ld      (shrinkler_d4+2), hl    ; written in little endian
        ld      hl, (shrinkler_d2)
        adc     hl, hl
        ld      (shrinkler_d2), hl
        jr      shrinkler_getbit1



-2 bytes onecall

shrinkler_readbit:
        ld      (shrinkler_d3+1), hl
shrinkler_d4l:
        ld      hl, 0
shrinkler_d4h:
        ld      de, #8000
shrinkler_rb0:
        adc     hl, hl
        ld      (shrinkler_d4l+1), hl
        ex      de, hl
        jr      nz, shrinkler_rb2
        adc     hl, hl
        jr      nz, shrinkler_rb3
shrinkler_rb1:
        ccf
        ld      d, (ix)
        ld      e, (ix+1)
        ex      de, hl
        inc     ix
        inc     ix
        jr      nc, shrinkler_rb1
        jr      shrinkler_rb0
shrinkler_rb2:
        adc     hl, hl
shrinkler_rb3:
        ld      (shrinkler_d4h+1), hl
shrinkler_d2:
        ld      hl, 0
        adc     hl, hl
        ld      (shrinkler_d2+1), hl
        jr      shrinkler_getbit1

antoniovillena

#92
-1 byte




shrinkler_readbit:
        ld      (shrinkler_d3+1), hl
shrinkler_d4l:
        ld      hl, 0
shrinkler_d4h:
        ld      de, #8000
shrinkler_rb0:
        adc     hl, hl
        ld      (shrinkler_d4l+1), hl
        ex      de, hl
        jr      nz, shrinkler_rb2-1
        adc     hl, hl
        jr      nz, shrinkler_rb3
shrinkler_rb1:
        ld      h, (ix)
        ld      l, (ix+1)
        inc     ix
        inc     ix
        ccf
        jr      c, shrinkler_rb0
        ex      de, hl
        jr      shrinkler_rb1-3
shrinkler_rb2:
        ld      l, d ; adc hl, hl with ed prefix
shrinkler_rb3:
        ld      (shrinkler_d4h+1), hl

antoniovillena

I have released a loader for ZX Spectrum with the one call version:

https://github.com/antoniovillena/zx7b/blob/master/shr8k.asm

So from a input binary file assembled with org $8000 you will have a compressed TAP file like this:

https://github.com/antoniovillena/zx7b/blob/master/demo.tap


antoniovillena

#94
This one can also applied to the recall version to be 254 bytes. I have both versions here:
https://github.com/antoniovillena/zx7b/blob/master/shrinkler.asm
https://github.com/antoniovillena/zx7b/blob/master/shrinkler_onecall.asm

Also put the shrinkler_decrunch routine first (to avoid call) and removed the shrinkler_d5 self modifying code from shrinkler.asm. Now this routine can work on ROM.

Quote from: antoniovillena on 16:13, 02 March 18
-1 byte




shrinkler_readbit:
        ld      (shrinkler_d3+1), hl
shrinkler_d4l:
        ld      hl, 0
shrinkler_d4h:
        ld      de, #8000
shrinkler_rb0:
        adc     hl, hl
        ld      (shrinkler_d4l+1), hl
        ex      de, hl
        jr      nz, shrinkler_rb2-1
        adc     hl, hl
        jr      nz, shrinkler_rb3
shrinkler_rb1:
        ld      h, (ix)
        ld      l, (ix+1)
        inc     ix
        inc     ix
        ccf
        jr      c, shrinkler_rb0
        ex      de, hl
        jr      shrinkler_rb1-3
shrinkler_rb2:
        ld      l, d ; adc hl, hl with ed prefix
shrinkler_rb3:
        ld      (shrinkler_d4h+1), hl


roudoudou

Madram joined the game and sent me a 209 bytes version, entirely rewritten and simplified


First page updated with the source

My pronouns are RASM and ACE

Targhan

Ahah, hooray for Madram! :)
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

GUNHED

That's very interesting... let me ask you one question...

In the recent decrunch routine there is the line:

probs=($+256)&#FF00

How would this be written in MAXAM? Or.. what does this mean?
http://futureos.de --> Get the revolutionary FutureOS (Update: 2023.11.30)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

Targhan

I guess it means : "probs" has the address of the next address aligned to 256.
$ is the current address. Let's say #1234
so "probs" is #1300.


I don't know Maxam well enough to "translate" this expression to it.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

GUNHED

#99
Thanks! That explains it.
In Maxam it would be close to this:

DS $/256*256+256-$
probs...

then next byte would be located at &XX00.  :)
http://futureos.de --> Get the revolutionary FutureOS (Update: 2023.11.30)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.12.26)

Powered by SMFPacks Menu Editor Mod