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

0 Members and 1 Guest are viewing this topic.

Offline Hicks

  • CPC664
  • ***
  • Posts: 80
  • Country: fr
    • Vanity
  • Liked: 155
  • Likes Given: 10
Re: Shrinkler Z80 decrunch routine
« Reply #25 on: 20:12, 03 February 18 »
-1 byte:

Code: [Select]
    ex de,hl
    ld hl,1 ; d7
shrinkler_bitsloop:
    exx
    call shrinkler_getbit
    exx
    adc hl,hl
    ld a,(de)
    sub 2
    ld (de),a
    jr nc,shrinkler_bitsloop
    ld b,h
    ld c,l
    ret

Becomes:

Code: [Select]
    ld bc,1
shrinkler_bitsloop:
    exx
    call shrinkler_getbit
    exx
    rl c : rl b
    ld a,(hl)
    sub 2
    ld (hl),a
    jr nc,shrinkler_bitsloop
    ret

Save CPU too.

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #26 on: 21:02, 03 February 18 »
valid! updated first post, blablabla
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 #27 on: 22:44, 03 February 18 »
-2 bytes. But without apply the last -1


Code: [Select]
shrinkler_decrunch:
        ld      (shrinkler_a5+1), hl


        ; Init range decoder state
        ld      hl, shrinkler_dr+1536*2+8
        ld      bc, 1536*2
        ld      (hl), c
        inc     hl
        ld      (hl), $80
        ld      de, shrinkler_dr+1536*2+7
        lddr
        ld      c, $08
        dec     hl
        lddr
        inc     (hl)


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6
        rl      (hl)
        jr      nc, shrinkler_getlit
shrinkler_a5:
        ld      de,  $1234
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit


        ; Reference
        sbc     hl, hl
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, $0101
        ld      de, (shrinkler_a5+1)
        add     hl, de
        ldir


        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ; retour systématique avec carry et HL=BC
        ld      hl, 3
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength
        ret


;--------------------------------------------------
shrinkler_getnumber:
        ; Out: Number in HL
        ld      hl, shrinkler_d6+1
        ld      (hl), a
        dec     hl
        ld      (hl), 0
shrinkler_numberloop:
        inc     (hl)
        inc     (hl)
        call    shrinkler_getbit
        jr      c, shrinkler_numberloop
        dec     (hl)
        ex      de, hl
        ld      hl, 1 ; d7
shrinkler_bitsloop:
        call    shrinkler_getbit
        adc     hl, hl
        ld      a, (de)
        sub     2
        ld      (de), a
        jr      nc, shrinkler_bitsloop
        ld      b, h
        ld      c, l
        ret


;--------------------------------------------------
        ; Out: Bit in C
shrinkler_readbit:
        ld      hl, (shrinkler_d4)
        add     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2) ; lu en little endian
        adc     hl, hl
        ex      af, af'
        ld      a, h
        or      l
        or      d
        or      e
        jr      nz, shrinkler_nonewword
        ; HL=DE=0
        ld      e, 4
        add     ix, de
        ld      l, (ix-1)
        ld      h, (ix-2)
        ld      e, (ix-3)
        ld      d, (ix-4)       ; DEHL=(a4) nouvelle valeur lue en big endian!
        ex      af, af'         ; injecte la CARRY précédente
        adc     hl, hl
        ex      hl, de
        adc     hl, hl
        ex      af, af'         ; save carry
shrinkler_nonewword:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; mais écrite en little endian
        ld      hl, shrinkler_d3
        sla     (hl)
        inc     hl
        rl      (hl)
        inc     hl
        ex      af, af'                 ; retrieve previous carry
        rl      (hl)
        inc     hl
        rl      (hl)
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
        ld      (shrinkler_a5+1), de
        xor     a
        ld      l, a
        inc     a
        and     e
        ld      h, a
shrinkler_altgetbit:
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      a, (shrinkler_d3+1)     ; obligé de relire les 8 bits forts la valeur...
        add     a, a
        jr      nc, shrinkler_readbit


        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, 4
shrinkler_shift4:
        srl     b
        rr      c
        dec     a
        jr      nz, shrinkler_shift4
        xor     a
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        ld      h, a
        ld      l, a
        ld      a, 16
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        dec     a
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        jr      c, shrinkler_one


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        pop     de
        jr      shrinkler_d3ret


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        pop     hl
        dec     a
        add     a, (hl)
        ld      (hl), a
        inc     hl
        ld      a, (hl)
        adc     a, $0f                  ; (a1)+#FFF
        ld      (hl), a
        scf                             ; SET CARRY
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #28 on: 22:48, 03 February 18 »
Corrected with the Hicks code:


Code: [Select]
shrinkler_decrunch:
        ld      (shrinkler_a5+1), hl


        ; Init range decoder state
        ld      hl, shrinkler_dr+1536*2+8
        ld      bc, 1536*2
        ld      (hl), c
        inc     hl
        ld      (hl), $80
        ld      de, shrinkler_dr+1536*2+7
        lddr
        ld      c, $08
        dec     hl
        lddr
        inc     (hl)


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6
        rl      (hl)
        jr      nc, shrinkler_getlit
shrinkler_a5:
        ld      de,  $1234
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit


        ; Reference
        sbc     hl, hl
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, $0101
        ld      de, (shrinkler_a5+1)
        add     hl, de
        ldir


        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ; retour systématique avec carry et HL=BC
        ld      hl, 3
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength
        ret


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


;--------------------------------------------------
        ; Out: Bit in C
shrinkler_readbit:
        ld      hl, (shrinkler_d4)
        add     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2) ; lu en little endian
        adc     hl, hl
        ex      af, af'
        ld      a, h
        or      l
        or      d
        or      e
        jr      nz, shrinkler_nonewword
        ; HL=DE=0
        ld      e, 4
        add     ix, de
        ld      l, (ix-1)
        ld      h, (ix-2)
        ld      e, (ix-3)
        ld      d, (ix-4)       ; DEHL=(a4) nouvelle valeur lue en big endian!
        ex      af, af'         ; injecte la CARRY précédente
        adc     hl, hl
        ex      hl, de
        adc     hl, hl
        ex      af, af'         ; save carry
shrinkler_nonewword:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; mais écrite en little endian
        ld      hl, shrinkler_d3
        sla     (hl)
        inc     hl
        rl      (hl)
        inc     hl
        ex      af, af'                 ; retrieve previous carry
        rl      (hl)
        inc     hl
        rl      (hl)
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
        ld      (shrinkler_a5+1), de
        xor     a
        ld      l, a
        inc     a
        and     e
        ld      h, a
shrinkler_altgetbit:
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      a, (shrinkler_d3+1)     ; obligé de relire les 8 bits forts la valeur...
        add     a, a
        jr      nc, shrinkler_readbit


        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, 4
shrinkler_shift4:
        srl     b
        rr      c
        dec     a
        jr      nz, shrinkler_shift4
        xor     a
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        ld      h, a
        ld      l, a
        ld      a, 16
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        dec     a
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        jr      c, shrinkler_one


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        pop     de
        jr      shrinkler_d3ret


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        pop     hl
        dec     a
        add     a, (hl)
        ld      (hl), a
        inc     hl
        ld      a, (hl)
        adc     a, $0f                  ; (a1)+#FFF
        ld      (hl), a
        scf                             ; SET CARRY
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #29 on: 22:57, 03 February 18 »
Another -1


Code: [Select]

shrinkler_decrunch:
        ld      (shrinkler_a5+1), hl


        ; Init range decoder state
        ld      hl, shrinkler_dr+1536*2+8
        ld      bc, 1536*2
        ld      (hl), c
        inc     hl
        ld      (hl), $80
        ld      de, shrinkler_dr+1536*2+7
        lddr
        ld      c, $08
        dec     hl
        lddr
        inc     (hl)


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6
        rl      (hl)
        jr      nc, shrinkler_getlit
shrinkler_a5:
        ld      de,  $1234
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit


        ; Reference
        sbc     hl, hl
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, $0101
        ld      de, (shrinkler_a5+1)
        add     hl, de
        ldir


        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ; retour systématique avec carry et HL=BC
        ld      hl, 2
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength
        ret


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


;--------------------------------------------------
        ; Out: Bit in C
shrinkler_readbit:
        ld      hl, (shrinkler_d4)
        add     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2) ; lu en little endian
        adc     hl, hl
        ex      af, af'
        ld      a, h
        or      l
        or      d
        or      e
        jr      nz, shrinkler_nonewword
        ; HL=DE=0
        ld      e, 4
        add     ix, de
        ld      l, (ix-1)
        ld      h, (ix-2)
        ld      e, (ix-3)
        ld      d, (ix-4)       ; DEHL=(a4) nouvelle valeur lue en big endian!
        ex      af, af'         ; injecte la CARRY précédente
        adc     hl, hl
        ex      hl, de
        adc     hl, hl
        ex      af, af'         ; save carry
shrinkler_nonewword:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; mais écrite en little endian
        ld      hl, shrinkler_d3
        sla     (hl)
        inc     hl
        rl      (hl)
        inc     hl
        ex      af, af'                 ; retrieve previous carry
        rl      (hl)
        inc     hl
        rl      (hl)
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
        ld      (shrinkler_a5+1), de
        xor     a
        ld      l, a
        inc     a
        and     e
        ld      h, a
shrinkler_altgetbit:
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      a, (shrinkler_d3+1)     ; obligé de relire les 8 bits forts la valeur...
        add     a, a
        jr      nc, shrinkler_readbit


        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, 4
shrinkler_shift4:
        srl     b
        rr      c
        dec     a
        jr      nz, shrinkler_shift4
        xor     a
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        ld      h, a
        ld      l, a
        ld      a, 16
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        dec     a
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        jr      c, shrinkler_one


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        pop     de
        jr      shrinkler_d3ret


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        pop     hl
        dec     a
        add     a, (hl)
        ld      (hl), a
        inc     hl
        ld      a, (hl)
        adc     a, $0f                  ; (a1)+#FFF
        ld      (hl), a
        scf                             ; SET CARRY
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #30 on: 23:01, 03 February 18 »
Another easy -1


Code: [Select]

shrinkler_decrunch:
        ld      (shrinkler_a5+1), hl


        ; Init range decoder state
        ld      hl, shrinkler_dr+1536*2+8
        ld      bc, 1536*2
        ld      (hl), c
        inc     hl
        ld      (hl), $80
        ld      de, shrinkler_dr+1536*2+7
        lddr
        ld      c, $08
        dec     hl
        lddr
        inc     (hl)


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6
        rl      (hl)
        jr      nc, shrinkler_getlit
shrinkler_a5:
        ld      de,  $1234
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit


        ; Reference
        sbc     hl, hl
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, $0101
        ld      de, (shrinkler_a5+1)
        add     hl, de
        ldir


        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ; return without carry and HL=BC
        ld      hl, 2
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength
        ret


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


;--------------------------------------------------
        ; Out: Bit in C
shrinkler_readbit:
        ld      hl, (shrinkler_d4)
        add     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2) ; lu en little endian
        adc     hl, hl
        ex      af, af'
        ld      a, h
        or      l
        or      d
        or      e
        jr      nz, shrinkler_nonewword
        ; HL=DE=0
        ld      e, 4
        add     ix, de
        ld      l, (ix-1)
        ld      h, (ix-2)
        ld      e, (ix-3)
        ld      d, (ix-4)       ; DEHL=(a4) nouvelle valeur lue en big endian!
        ex      af, af'         ; injecte la CARRY précédente
        adc     hl, hl
        ex      hl, de
        adc     hl, hl
        ex      af, af'         ; save carry
shrinkler_nonewword:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; mais écrite en little endian
        ld      hl, shrinkler_d3
        sla     (hl)
        inc     hl
        rl      (hl)
        inc     hl
        ex      af, af'                 ; retrieve previous carry
        rl      (hl)
        inc     hl
        rl      (hl)
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
        ld      (shrinkler_a5+1), de
        xor     a
        ld      l, a
        inc     a
        and     e
        ld      h, a
shrinkler_altgetbit:
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      a, (shrinkler_d3+1)     ; obligé de relire les 8 bits forts la valeur...
        add     a, a
        jr      nc, shrinkler_readbit


        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, 4
shrinkler_shift4:
        srl     b
        rr      c
        dec     a
        jr      nz, shrinkler_shift4
        xor     a
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        ld      h, a
        ld      l, a
        ld      a, 16
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        dec     a
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        jr      c, shrinkler_one


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        pop     de
        jr      shrinkler_d3ret


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        pop     hl
        dec     a
        add     a, (hl)
        ld      (hl), a
        inc     hl
        ld      a, (hl)
        adc     a, $0f                  ; (a1)+#FFF
        ld      (hl), a
        scf                             ; SET CARRY
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #31 on: 23:06, 03 February 18 »
the JP P does not work because the overflow may occur at the first DEC (hl)


BTW for short modif is it possible to post only a few lines?  ;D
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 #32 on: 23:16, 03 February 18 »
the JP P does not work because the overflow may occur at the first DEC (hl)


BTW for short modif is it possible to post only a few lines?  ;D


Sorry. This is the last time I do with this -1


Code: [Select]

shrinkler_decrunch:
        ld      (shrinkler_a5+1), hl


        ; Init range decoder state
        ld      hl, shrinkler_dr+1536*2+8
        ld      bc, 1536*2
        ld      (hl), c
        inc     hl
        ld      (hl), $80
        ld      de, shrinkler_dr+1536*2+7
        lddr
        ld      c, $08
        dec     hl
        lddr
        inc     (hl)


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6
        rl      (hl)
        jr      nc, shrinkler_getlit
shrinkler_a5:
        ld      de,  $1234
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit


        ; Reference
        sbc     hl, hl
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, $0101
        ld      de, (shrinkler_a5+1)
        add     hl, de
        ldir


        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ; return without carry and HL=BC
        ld      hl, 2
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength
        ret


;--------------------------------------------------
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:
        ld      hl, (shrinkler_d4)
        add     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2) ; lu en little endian
        adc     hl, hl
        ex      af, af'
        ld      a, h
        or      l
        or      d
        or      e
        jr      nz, shrinkler_nonewword
        ; HL=DE=0
        ld      e, 4
        add     ix, de
        ld      l, (ix-1)
        ld      h, (ix-2)
        ld      e, (ix-3)
        ld      d, (ix-4)       ; DEHL=(a4) nouvelle valeur lue en big endian!
        ex      af, af'         ; injecte la CARRY précédente
        adc     hl, hl
        ex      hl, de
        adc     hl, hl
        ex      af, af'         ; save carry
shrinkler_nonewword:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; mais écrite en little endian
        ld      hl, shrinkler_d3
        sla     (hl)
        inc     hl
        rl      (hl)
        inc     hl
        ex      af, af'                 ; retrieve previous carry
        rl      (hl)
        inc     hl
        rl      (hl)
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
        ld      (shrinkler_a5+1), de
        xor     a
        ld      l, a
        inc     a
        and     e
        ld      h, a
shrinkler_altgetbit:
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      a, (shrinkler_d3+1)     ; obligé de relire les 8 bits forts la valeur...
        add     a, a
        jr      nc, shrinkler_readbit


        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, 4
shrinkler_shift4:
        srl     b
        rr      c
        dec     a
        jr      nz, shrinkler_shift4
        xor     a
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        ld      h, a
        ld      l, a
        ld      a, 16
shrinkler_muluw:
        add     hl, hl
        rl      e
        rl      d
        jr      nc, shrinkler_cont
        add     hl, bc
        jr      nc, shrinkler_cont
        inc     de
shrinkler_cont:
        dec     a
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        jr      c, shrinkler_one


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        pop     de
        jr      shrinkler_d3ret


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        pop     hl
        dec     a
        add     a, (hl)
        ld      (hl), a
        inc     hl
        ld      a, (hl)
        adc     a, $0f                  ; (a1)+#FFF
        ld      (hl), a
        scf                             ; SET CARRY
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #33 on: 23:37, 03 February 18 »
thanks, the LD BC,1 upper works
now it's 292 bytes :)
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 #34 on: 23:52, 03 February 18 »
Another -1
Code: [Select]

        ld      a, $e0
shrinkler_shift4:
        srl     b
        rr      c
        add     a, a
        jr      c, shrinkler_shift4
        ex      hl, de

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #35 on: 23:59, 03 February 18 »
About this 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


Never fails. Because you only need to load up to 16 bits in bc and with positive range you have up to 63 (positive range is between 0 and 127)

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #36 on: 00:03, 04 February 18 »

i can't get it work with my test file. Maybe i miss a modif?
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 #37 on: 00:12, 04 February 18 »
i can't get it work with my test file. Maybe i miss a modif?


Send me your file and I can try. Another -1


Code: [Select]

        ld      a, $e1
shrinkler_shift4:
        srl     b
        rr      c
        add     a, a
        jr      c, shrinkler_shift4
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        ld      h, 0
        ld      l, h
shrinkler_muluw:
        add     hl, hl

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #38 on: 00:16, 04 February 18 »
Attached my test. It's a ZX Spectrum screen. Use sjasmplus as assembler

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #39 on: 00:21, 04 February 18 »
Attached my test. It's a ZX Spectrum screen. Use sjasmplus as assembler
there is no manic.shr in the archive


here is my shr. Expect 16384 bytes in output (Amstrad screen)
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 #40 on: 00:34, 04 February 18 »
I can not decompress 32k. Check if the first 14k are ok. manic.shr is generated by compressor.


I will migrate in the future to Ticks

http://retrolandia.net/foro/showthread.php?tid=43&pid=654#pid654

Because I would like to release a speed optimized version and this tool count the Z80 cycles of the whole execution. Also generate files to compare if the file is good extracted.
« Last Edit: 01:46, 04 February 18 by antoniovillena »

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #41 on: 00:42, 04 February 18 »
I get it, that changed the carry (always setted to always reset) now it works!


288 bytes
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 #42 on: 01:01, 04 February 18 »
I get it, that changed the carry (always setted to always reset) now it works!


288 bytes


Now tested with Ticks. It costs 21.642.848 cycles decrounch your file. Attached if can be useful for you.

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #43 on: 01:09, 04 February 18 »

Now tested with Ticks. It costs 21.642.848 cycles decrounch your file. Attached if can be useful for you.


CPC emulators can "tick" on demand.
On Amstrad machines we have wait-states so the final count is higher. 5.834.708 nops that to say 23.338.832 cycles
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 #44 on: 01:36, 04 February 18 »

CPC emulators can "tick" on demand.
On Amstrad machines we have wait-states so the final count is higher. 5.834.708 nops that to say 23.338.832 cycles


Yes. Also Spectrum emulators have contention. But it's a good number for compare with other algorithms.



The next one compares compression ratio with other algorithms.
Numbers are filesizes in bytes.

Code: [Select]
Size    Shrinkler Exomizer    aPLib   saukav     zx7b  BBuster
lena1k        776      812      872      873      902      905
lena16k     13796    13581    14635    14649    14689    14798
lena32k     28368    28019    29991    30071    30272    30446
alice1k       548      613      617      611      631      636
alice16k     6872     7266     7659     7738     8175     8429
alice32k    12868    13461    14473    14535    16074    16570
128rom1k      840      884      889      913      923      925
128rom16k   11848    12260    12434    12728    12806    12882
128rom32k   23648    24415    24820    26157    26524    26708


This last table compares speed with other algorithms.
Numbers are execution cycles.

Code: [Select]
           Shrinkler  deexov4    aPLib  BBuster  zx7mega   saukav   zx7bf2
--------------------------------------------------------------------------
lena1k      13757267   303436   176642   106746    95255    76547    81040
lena16k    238317371  4407913  2961621  1908398  1727095  1646032  1462568
lena32k    484967405  8443253  5820921  3651800  3300486  3231882  2803116
alice1k     10060954   274111   136224    98914    89385    70869    73459
alice16k   131592504  2973592  2143122  1812259  1614225  1338287  1328886
alice32k   249719379  5378511  4189855  3614393  3230255  2550243  2654236
128rom1k    13773150   249124   131667    82637    74110    60222    62000
128rom16k  197319929  3571407  2292945  1550682  1407478  1392317  1180569
128rom32k  394594060  7355277  4583902  3107867  2825773  1926027  2381847
--------------------------------------------------------------------------
routine size     288      201      197      168      244     ~200      191


https://github.com/antoniovillena/zx7b
« Last Edit: 01:45, 04 February 18 by antoniovillena »

Offline antoniovillena

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


Code: [Select]

        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        pop     bc
        jr      c, shrinkler_one


shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        jr      shrinkler_d3ret


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        ld      a, (bc)
        sub     1
        ld      (bc), a
        inc     bc
        ld      a, (bc)
        sbc     a, $f0                  ; (a1)+#FFF
        ld      (bc), a
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline antoniovillena

  • CPC664
  • ***
  • Posts: 87
  • Liked: 88
  • Likes Given: 3
Re: Shrinkler Z80 decrunch routine
« Reply #46 on: 03:20, 04 February 18 »
Another -1


Code: [Select]

        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        sbc     hl, hl
shrinkler_muluw:
        add     hl, hl


Total: 286 bytes

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #47 on: 09:46, 04 February 18 »
Code: [Select]
Size    Shrinkler Exomizer    aPLib   saukav     zx7b  BBuster


Didn't know about saukav vs zx7b and his performance, i will add it to my assembler for on the fly data/code compression
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 #48 on: 12:09, 04 February 18 »
Another -1. I'm sorry this time I put whole code because reordering. Basically you can avoid the final ret by putting dummy routine.


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:
        ld      hl, (shrinkler_d4)
        add     hl, hl
        ex      de, hl
        ld      hl, (shrinkler_d4+2) ; lu en little endian
        adc     hl, hl
        ex      af, af'
        ld      a, h
        or      l
        or      d
        or      e
        jr      nz, shrinkler_nonewword
        ; HL=DE=0
        ld      e, 4
        add     ix, de
        ld      l, (ix-1)
        ld      h, (ix-2)
        ld      e, (ix-3)
        ld      d, (ix-4)       ; DEHL=(a4) nouvelle valeur lue en big endian!
        ex      af, af'         ; injecte la CARRY précédente
        adc     hl, hl
        ex      hl, de
        adc     hl, hl
        ex      af, af'         ; save carry
shrinkler_nonewword:
        ld      (shrinkler_d4), de
        ld      (shrinkler_d4+2), hl    ; mais écrite en little endian
        ld      hl, shrinkler_d3
        rl      (hl)
        inc     hl
        rl      (hl)
        inc     hl
        ex      af, af'                 ; retrieve previous carry
        rl      (hl)
        inc     hl
        rl      (hl)
        jr      shrinkler_getbit1


;--------------------------------------------------
shrinkler_getkind:
        ;Use parity as context
        ld      (shrinkler_a5+1), de
        xor     a
        ld      l, a
        inc     a
        and     e
        ld      h, a
shrinkler_altgetbit:
        ld      (shrinkler_d6), hl


shrinkler_getbit:
        exx
shrinkler_getbit1:
        ld      a, (shrinkler_d3+1)     ; obligé de relire les 8 bits forts la valeur...
        add     a, a
        jr      nc, shrinkler_readbit


        ld      hl, (shrinkler_d6)
        add     hl, hl
        ld      de, shrinkler_pr+2      ; cause -1 context
        add     hl, de
        push    hl
        ld      e, (hl)
        inc     hl
        ld      d, (hl)
        ; D1 = One prob
        push    de
        ld      b, d
        ld      c, e            ; bc=de=d1 / hl=a1
        ld      a, $e1
shrinkler_shift4:
        srl     b
        rr      c
        add     a, a
        jr      c, shrinkler_shift4
        ex      hl, de
        sbc     hl, bc          ; hl=d1-d1/16
        ex      hl, de
        ld      (hl), d
        dec     hl
        ld      (hl), e
        pop     bc              ; bc=d1 initial
        ld      de, (shrinkler_d3)
; input: DE x BC
; output: DEHL
        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:
        dec     a
        jr      nz, shrinkler_muluw
        ld      hl, (shrinkler_d2)
        xor     a
        sbc     hl, de
        pop     bc
        jr      c, shrinkler_one




shrinkler_zero:
        ; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
        ld      (shrinkler_d2), hl
        ld      hl, (shrinkler_d3)
        sbc     hl, de
        jr      shrinkler_d3ret




shrinkler_decrunch:
        ld      (shrinkler_a5+1), hl


        ; Init range decoder state
        ld      hl, shrinkler_dr+1536*2+8
        ld      bc, 1536*2
        ld      (hl), c
        inc     hl
        ld      (hl), $80
        ld      de, shrinkler_dr+1536*2+7
        lddr
        ld      c, 8
        dec     hl
        lddr
        inc     (hl)


shrinkler_lit:
        ; Literal
        scf
shrinkler_getlit:
        call    nc, shrinkler_getbit
        ld      hl, shrinkler_d6
        rl      (hl)
        jr      nc, shrinkler_getlit
shrinkler_a5:
        ld      de,  $1234
        ldi


        ; After literal
        call    shrinkler_getkind
        jr      nc, shrinkler_lit


        ; Reference
        sbc     hl, hl
        call    shrinkler_altgetbit
        jr      nc, shrinkler_readoffset
shrinkler_readlength:
        ld      a, 4
        call    shrinkler_getnumber
shrinkler_d5:
        ld      hl, $0101
        ld      de, (shrinkler_a5+1)
        add     hl, de
        ldir


        ; After reference
        call    shrinkler_getkind
        jr      nc, shrinkler_lit
shrinkler_readoffset:
        ld      a, 3
        call    shrinkler_getnumber
        ; return without carry and HL=BC
        ld      hl, 2
        sbc     hl, bc
        ld      (shrinkler_d5+1), hl
        jr      nz, shrinkler_readlength


shrinkler_one:
        ; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
        ; move+add out of order!
        ld      a, (bc)
        sub     1
        ld      (bc), a
        inc     bc
        ld      a, (bc)
        sbc     a, $f0                  ; (a1)+#FFF
        ld      (bc), a
        ex      de, hl
shrinkler_d3ret:
        ld      (shrinkler_d3), hl
        exx
        ret

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 890
  • Country: fr
    • urban exploration
  • Liked: 1189
  • Likes Given: 738
Re: Shrinkler Z80 decrunch routine
« Reply #49 on: 15:12, 04 February 18 »
But the shrinkler_one function is not dummy since it will makes 2 writes in adress 2 and adress 3


So i switch shrinkler_zero, shrinkler_one and the JR Then only shrinkler_d3 is written with garbage, not the memory elsewhere
use RASM, the best assembler ever made :p

I will survive