Author Topic: Shrinkler Z80 decrunch routine  (Read 14889 times)

0 Members and 2 Guests are viewing this topic.

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.022
  • Country: fr
    • urban exploration
  • Liked: 1395
  • Likes Given: 826
Re: Shrinkler Z80 decrunch routine
« Reply #75 on: 09:14, 20 February 18 »
great! I will update official sources tonight after testing!
use RASM, the best assembler ever made :p

I will survive

Offline Urusergi

  • CPC6128
  • ****
  • Posts: 244
  • Country: es
  • Liked: 491
  • Likes Given: 1660
Re: Shrinkler Z80 decrunch routine
« Reply #76 on: 23:03, 20 February 18 »
-6 bytes
Code: [Select]
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:

Code: [Select]
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

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.022
  • Country: fr
    • urban exploration
  • Liked: 1395
  • Likes Given: 826
Re: Shrinkler Z80 decrunch routine
« Reply #77 on: 01:13, 21 February 18 »
thanks, i updated first post with 255 bytes (one call version) and 262 bytes (multiple calls version)


now, source=IX and destination=DE
use RASM, the best assembler ever made :p

I will survive

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #78 on: 01:46, 21 February 18 »
-6 bytes


Incredible. You broke the 256 bytes barrier

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #79 on: 02:34, 21 February 18 »
Another -1


Code: [Select]

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


Code: [Select]

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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #80 on: 03:23, 21 February 18 »
-3 bytes in onecall version if shrinkler_pr is even with this code:


Code: [Select]

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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #81 on: 03:30, 21 February 18 »
same lenght without even condition:


Code: [Select]

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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #82 on: 03:46, 21 February 18 »
-1 byte
Code: [Select]

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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #83 on: 04:25, 21 February 18 »
-2 bytes to the recall version:


Code: [Select]

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

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.022
  • Country: fr
    • urban exploration
  • Liked: 1395
  • Likes Given: 826
Re: Shrinkler Z80 decrunch routine
« Reply #84 on: 10:29, 21 February 18 »
 ;D  like it!


first post updated with 250 bytes onecall and 259 bytes recall versions
use RASM, the best assembler ever made :p

I will survive

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #85 on: 13:02, 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


Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #86 on: 23:42, 21 February 18 »
-1 byte. Sorry, complete code
Code: [Select]

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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #87 on: 02:01, 26 February 18 »
Another -1
Code: [Select]

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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #88 on: 03:37, 26 February 18 »
Another -1
Code: [Select]
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


Code: [Select]
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ld      a, 4
        ret

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #89 on: 04:16, 26 February 18 »
Quote
I 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).
« Last Edit: 12:24, 26 February 18 by antoniovillena »

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.022
  • Country: fr
    • urban exploration
  • Liked: 1395
  • Likes Given: 826
Re: Shrinkler Z80 decrunch routine
« Reply #90 on: 14:20, 26 February 18 »
Interresting, i'll try tonight (and i hope i will find test files which work and not!)
use RASM, the best assembler ever made :p

I will survive

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #91 on: 16:49, 28 February 18 »
-1 byte recall
Code: [Select]
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
Code: [Select]
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

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #92 on: 17:13, 02 March 18 »
-1 byte


Code: [Select]

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
« Last Edit: 17:21, 02 March 18 by antoniovillena »

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #93 on: 19:35, 02 March 18 »
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


Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #94 on: 16:07, 03 March 18 »
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.

-1 byte


Code: [Select]

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
« Last Edit: 16:09, 03 March 18 by antoniovillena »

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.022
  • Country: fr
    • urban exploration
  • Liked: 1395
  • Likes Given: 826
Re: Shrinkler Z80 decrunch routine
« Reply #95 on: 20:37, 07 April 18 »
Madram joined the game and sent me a 209 bytes version, entirely rewritten and simplified


First page updated with the source

use RASM, the best assembler ever made :p

I will survive

Offline Targhan

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.322
  • Country: fr
  • Liked: 1244
  • Likes Given: 186
Re: Shrinkler Z80 decrunch routine
« Reply #96 on: 20:56, 07 April 18 »
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

Offline GUNHED

  • 6128 Plus
  • ******
  • Posts: 2.493
  • Country: de
  • Reincarnation of TFM
    • FutureOS - The quickest OS for the CPC and Plus
  • Liked: 1183
  • Likes Given: 2805
Re: Shrinkler Z80 decrunch routine
« Reply #97 on: 18:09, 19 August 18 »
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 (Recent update: 2021.01.24)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.05.02)

Offline Targhan

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.322
  • Country: fr
  • Liked: 1244
  • Likes Given: 186
Re: Shrinkler Z80 decrunch routine
« Reply #98 on: 20:32, 19 August 18 »
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

Offline GUNHED

  • 6128 Plus
  • ******
  • Posts: 2.493
  • Country: de
  • Reincarnation of TFM
    • FutureOS - The quickest OS for the CPC and Plus
  • Liked: 1183
  • Likes Given: 2805
Re: Shrinkler Z80 decrunch routine
« Reply #99 on: 17:25, 21 August 18 »
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.  :)
« Last Edit: 17:30, 21 August 18 by GUNHED »
http://futureos.de --> Get the revolutionary FutureOS (Recent update: 2021.01.24)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.05.02)