1930 lines
46 KiB
NASM
1930 lines
46 KiB
NASM
; ============================================================================
|
||
; inflate.asm — TSConfig gzip inflate (adapted from SamFlate by Andrew Collier)
|
||
;
|
||
; Original SamFlate (C) 2009, released under DFSG-compatible license (BSD/GPL).
|
||
; TSConfig adaptation: replaces SAM Coupe LMPR/HMPR paging with TSConfig
|
||
; page-window port I/O (0x10AF–0x13AF).
|
||
;
|
||
; Memory layout during decompression (interrupts disabled):
|
||
; Win 0 (0x0000–0x3FFF): Source VGZ data (rotating pages)
|
||
; Win 1 (0x4000–0x7FFF): Source VGZ next page (contiguous 32K src window)
|
||
; Temporarily: backref history (dest_page - 1) during LDIR
|
||
; Win 2 (0x8000–0xBFFF): Decode working buffer (fixed page PAGE_DECODE)
|
||
; Win 3 (0xC000–0xFFFF): This code + RAM tables (extra WMF page)
|
||
;
|
||
; SamFlate was designed for SAM Coupe where LMPR gives a 32K contiguous
|
||
; source window (sections A+B). On TSConfig, Win 0+Win 1 together provide
|
||
; the same 32K window so that source reads never fall off the page boundary
|
||
; between output flushes. Win 1 is briefly remapped for backref LDIR, then
|
||
; immediately restored to src_page + 1.
|
||
;
|
||
; Entry: Called via JP 0xC200 (inflate_init) from inflate_call.s
|
||
; A = source start physical page (e.g. #A1 for TAP)
|
||
; E = destination start physical page (e.g. #20 for megabuffer)
|
||
; D = saved Win 2 page (to restore on exit)
|
||
; SP = safe stack in Win 3 area (e.g. #FFF0)
|
||
; Return address already pushed on stack by caller
|
||
;
|
||
; Exit: RET with A=0 carry clear (success) or A!=0 carry set (error).
|
||
; Win 2 restored to saved page. Caller restores Win 0/1/3.
|
||
;
|
||
; Assembled with sjasmplus -> raw binary, loaded as extra WMF page.
|
||
; NOTE: first 257 bytes at 0xC000 may be overwritten during inflate
|
||
; (DEFLATE dict copy overflow). Entry code runs once before inflate.
|
||
; ============================================================================
|
||
|
||
DEVICE NOSLOT64K
|
||
ORG #C000
|
||
|
||
; -- TSConfig port equates ---------------------------------------------------
|
||
PORT_W0 EQU #10AF
|
||
PORT_W1 EQU #11AF
|
||
PORT_W2 EQU #12AF
|
||
PAGE_DECODE EQU #EA ; free page for decode buffer
|
||
|
||
; -- Debug port equates (emulator shows 'Illegal port! OUT') ----------------
|
||
DBG_STATUS EQU #FFAF ; status/milestone code
|
||
DBG_SRC EQU #FEAF ; current src page
|
||
DBG_DST EQU #FDAF ; current dst page
|
||
|
||
; -- Macro: emit debug milestone (destroys BC, A) ---------------------------
|
||
MACRO DBG_OUT val
|
||
IFDEF DBG_ENABLE
|
||
ld a, val
|
||
ld bc, DBG_STATUS
|
||
out (c), a
|
||
ENDIF
|
||
ENDM
|
||
|
||
; -- Macro: emit debug milestone + src/dst pages (destroys BC, A) -----------
|
||
MACRO DBG_OUT_PAGES val
|
||
IFDEF DBG_ENABLE
|
||
ld a, val
|
||
ld bc, DBG_STATUS
|
||
out (c), a
|
||
ld a, (src_page + 1)
|
||
ld bc, DBG_SRC
|
||
out (c), a
|
||
ld a, (dst_page + 1)
|
||
ld bc, DBG_DST
|
||
out (c), a
|
||
ENDIF
|
||
ENDM
|
||
|
||
; -- Macro: write A to TSConfig page window port (destroys BC) ---------------
|
||
MACRO OUT_W0
|
||
ld bc, PORT_W0
|
||
out (c), a
|
||
ENDM
|
||
|
||
MACRO OUT_W1
|
||
ld bc, PORT_W1
|
||
out (c), a
|
||
ENDM
|
||
|
||
MACRO OUT_W2
|
||
ld bc, PORT_W2
|
||
out (c), a
|
||
ENDM
|
||
|
||
; -- Macro: unrolled Huffman decode body -------------------------------------
|
||
MACRO HUFFDEC lbl, mode, tgt
|
||
lbl:
|
||
exx
|
||
IF mode > 0
|
||
dec b
|
||
or a
|
||
rr c
|
||
ELSE
|
||
or a
|
||
rr c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
ENDIF
|
||
exx
|
||
adc a, a
|
||
add a, a
|
||
ld l, a
|
||
ld a, (hl)
|
||
bit 7, a
|
||
jp z, tgt
|
||
inc hl
|
||
ld h, (hl)
|
||
ENDM
|
||
|
||
|
||
; ============================================================================
|
||
; ENTRY POINT (0xC000) -- JP to safe init zone
|
||
;
|
||
; This 3-byte JP may be overwritten by DEFLATE backref LDIR overflow
|
||
; (up to 258 bytes past 0xBFFF). That's fine: by the time the overflow
|
||
; happens, we've already jumped to init and are deep inside inflate_core.
|
||
;
|
||
; inflate_call.s calls JP 0xC200 directly (inflate_init in safe zone).
|
||
; The JP at 0xC000 is NOT used at runtime; it exists only as a
|
||
; fallback marker and will be overwritten by LDIR on first call.
|
||
; ============================================================================
|
||
entry:
|
||
jp inflate_init
|
||
|
||
; ============================================================================
|
||
; PADDING — survive DEFLATE backref overflow
|
||
;
|
||
; During LDIR of a backref copy, DE can advance up to 258 bytes
|
||
; past 0xBFFF into Win 3 (0xC000+), overwriting inflate code.
|
||
; inflate_init MUST start at or after 0xC102 to survive.
|
||
; We place it at 0xC200 for a clean round address.
|
||
; ============================================================================
|
||
DS #C1F0 - $, 0
|
||
|
||
; ── Progress bar parameter block ────────────────────────────────────────
|
||
; Written by inflate_call.s before JP 0xC200.
|
||
; Safe from LDIR overflow (max 258 bytes → 0xC102 < 0xC1F0).
|
||
;
|
||
; inflate_call.s uses absolute addresses 0xC1F0–0xC1F7 to write these.
|
||
; ────────────────────────────────────────────────────────────────────────
|
||
pb_text_pg: DB 0 ; 0xC1F0: text screen physical page
|
||
pb_attr_lo: DB 0 ; 0xC1F1: attr base offset low byte (bit7=1, attr area)
|
||
pb_attr_hi: DB 0 ; 0xC1F2: attr base offset high byte
|
||
pb_total: DB 0 ; 0xC1F3: estimated total output pages (0=disabled)
|
||
pb_bar_w: DB 0 ; 0xC1F4: bar width in columns
|
||
pb_green: DB 0 ; 0xC1F5: green attr value
|
||
pb_error: DB 0 ; 0xC1F6: Bresenham error accumulator (runtime)
|
||
pb_col: DB 0 ; 0xC1F7: current filled column (runtime)
|
||
|
||
ASSERT $ <= #C200, "progress block overflows past inflate_init!"
|
||
DS #C200 - $, 0
|
||
|
||
; ============================================================================
|
||
; INFLATE INIT — safe zone (≥ 0xC102), runs every call
|
||
;
|
||
; Registers on entry:
|
||
; A = source start physical page
|
||
; E = destination start physical page
|
||
; D = saved Win 2 page (to restore on exit)
|
||
; SP = safe stack in Win 3 area
|
||
; Return address already pushed on stack
|
||
; ============================================================================
|
||
inflate_init:
|
||
ASSERT $ == #C200, "inflate_init must be at exactly 0xC200 (inflate_call.s hardcodes this)"
|
||
; A = src start page, D = saved pg2, E = dst start page
|
||
ld (src_page + 1), a
|
||
ld a, d
|
||
ld (wc_saved_pg2 + 1), a
|
||
ld a, e
|
||
ld (dst_page + 1), a
|
||
sub 2
|
||
ld (dst_page_m2 + 1), a
|
||
|
||
; Initial destination offset = 0
|
||
ld hl, 0
|
||
ld (dst + 1), hl
|
||
|
||
; Remap Win 2 = decode buffer page
|
||
ld a, PAGE_DECODE
|
||
OUT_W2
|
||
|
||
; Remap Win 0+1 = first two source pages (32K contiguous window)
|
||
ld a, (src_page + 1)
|
||
OUT_W0
|
||
inc a
|
||
ld b, HIGH PORT_W1 ; C still = #AF from OUT_W0
|
||
out (c), a ; Win 1 = src_page + 1
|
||
|
||
; Source pointer at start of Win 0, decode buffer at 0x8000
|
||
ld hl, #0000
|
||
ld de, #8000
|
||
; fall through to inflate_core
|
||
|
||
; ============================================================================
|
||
; INFLATE CORE -- gzip header parse + DEFLATE blocks
|
||
; ============================================================================
|
||
inflate_core:
|
||
ld (interim_dst + 1), de
|
||
|
||
; HL'/C'/B' = source state (alternate registers)
|
||
ld c, (hl)
|
||
inc hl
|
||
ld b, 8
|
||
exx
|
||
|
||
; -- gzip header --
|
||
call read8bits
|
||
cp #1F
|
||
jp nz, fail
|
||
call read8bits
|
||
cp #8B
|
||
jp nz, fail
|
||
call read8bits
|
||
cp 8
|
||
jp nz, fail
|
||
|
||
call read8bits
|
||
ld d, a ; flags
|
||
ld a, 6
|
||
call dropbytes
|
||
|
||
ld a, d
|
||
and #04
|
||
call nz, drop_gz_fextra
|
||
ld a, d
|
||
and #08
|
||
call nz, drop_gz_fname
|
||
ld a, d
|
||
and #10
|
||
call nz, drop_gz_fcomment
|
||
ld a, d
|
||
and #02
|
||
call nz, drop_gz_fhcrc
|
||
|
||
|
||
; -- DEFLATE block loop ------------------------------------------------------
|
||
; DBG: 0x12 = gzip header parsed OK, entering DEFLATE blocks
|
||
DBG_OUT #12
|
||
|
||
NEW_BLOCK:
|
||
call read1bit
|
||
ld (this_was_last_block + 1), a
|
||
call read2bits
|
||
cp 3
|
||
jp z, fail
|
||
cp 1
|
||
jp c, blocktype0
|
||
jp z, blocktype1
|
||
jp blocktype2
|
||
|
||
|
||
; ============================================================================
|
||
; BLOCK TYPE 0 -- stored (raw) data
|
||
; ============================================================================
|
||
blocktype0:
|
||
DBG_OUT #14
|
||
call readalign
|
||
call read8bits
|
||
ld c, a
|
||
call read8bits
|
||
ld b, a
|
||
call read8bits
|
||
ld l, a
|
||
call read8bits
|
||
ld h, a
|
||
or a
|
||
sbc hl, bc
|
||
ld a, h
|
||
or l
|
||
jp nz, fail
|
||
|
||
ld de, (interim_dst + 1)
|
||
|
||
bt0_try_page:
|
||
ld l, e
|
||
ld h, d
|
||
add hl, bc
|
||
ld a, h
|
||
sub #80
|
||
cp #40
|
||
jp c, bt0_fits
|
||
|
||
; Won't fit: flush page
|
||
ld hl, #C000
|
||
or a
|
||
sbc hl, de
|
||
ld a, l
|
||
ld l, c
|
||
ld c, a
|
||
ld a, h
|
||
ld h, b
|
||
ld b, a
|
||
or a
|
||
sbc hl, bc
|
||
ld (bt0_remaining + 1), hl
|
||
|
||
exx
|
||
push hl
|
||
exx
|
||
pop hl
|
||
ldir
|
||
push hl
|
||
exx
|
||
pop hl
|
||
exx
|
||
|
||
; Copy decode buffer -> destination
|
||
ld a, (dst_page + 1)
|
||
OUT_W0
|
||
|
||
ld de, (dst + 1)
|
||
ld a, e
|
||
or d
|
||
jr z, bt0_whole
|
||
|
||
ld hl, #4000
|
||
or a
|
||
sbc hl, de
|
||
ld c, l
|
||
ld b, h
|
||
ld l, e
|
||
ld a, d
|
||
or #80
|
||
ld h, a
|
||
ldir
|
||
jr bt0_flushed
|
||
|
||
bt0_whole:
|
||
ld hl, #8000
|
||
ld de, #0000
|
||
ld bc, #4000
|
||
ldir
|
||
|
||
bt0_flushed:
|
||
ld hl, 0
|
||
ld (dst + 1), hl
|
||
ld a, (dst_page + 1)
|
||
inc a
|
||
cp #60 ; megabuffer limit (0x20-0x5F)
|
||
jp nc, fail ; overflow → abort
|
||
ld (dst_page + 1), a
|
||
dec a
|
||
dec a
|
||
ld (dst_page_m2 + 1), a
|
||
|
||
; DBG: 0x20 = bt0 page flushed
|
||
DBG_OUT_PAGES #20
|
||
|
||
; Source rollover
|
||
exx
|
||
bit 6, h
|
||
jr z, bt0_no_srcroll
|
||
ld a, h
|
||
and #3F
|
||
ld h, a
|
||
ld a, (src_page + 1)
|
||
inc a
|
||
ld (src_page + 1), a
|
||
bt0_no_srcroll:
|
||
exx
|
||
|
||
ld a, (src_page + 1)
|
||
OUT_W0
|
||
inc a
|
||
ld b, HIGH PORT_W1 ; C still = #AF from OUT_W0
|
||
out (c), a ; Win 1 = src_page + 1
|
||
call progress_update
|
||
|
||
ld de, #8000
|
||
bt0_remaining EQU $
|
||
ld bc, #0000
|
||
jp bt0_try_page
|
||
|
||
bt0_fits:
|
||
exx
|
||
push hl
|
||
exx
|
||
pop hl
|
||
ldir
|
||
push hl
|
||
exx
|
||
pop hl
|
||
exx
|
||
ld (interim_dst + 1), de
|
||
jp END_BLOCK
|
||
|
||
|
||
; ============================================================================
|
||
; BLOCK TYPE 1 -- static Huffman
|
||
; ============================================================================
|
||
blocktype1:
|
||
DBG_OUT #15
|
||
ld hl, 288
|
||
ld (literals + 1), hl
|
||
ld a, 32
|
||
ld (distances + 1), a
|
||
|
||
ld hl, codelengths
|
||
ld b, 144
|
||
ld a, 8
|
||
bt1_s1: ld (hl), a
|
||
inc hl
|
||
djnz bt1_s1
|
||
ld b, 112
|
||
ld a, 9
|
||
bt1_s2: ld (hl), a
|
||
inc hl
|
||
djnz bt1_s2
|
||
ld b, 24
|
||
ld a, 7
|
||
bt1_s3: ld (hl), a
|
||
inc hl
|
||
djnz bt1_s3
|
||
ld b, 8
|
||
ld a, 8
|
||
bt1_s4: ld (hl), a
|
||
inc hl
|
||
djnz bt1_s4
|
||
jp huffman_common
|
||
|
||
|
||
; ============================================================================
|
||
; BLOCK TYPE 2 -- dynamic Huffman
|
||
; ============================================================================
|
||
blocktype2:
|
||
DBG_OUT #16
|
||
call read5bits
|
||
inc a
|
||
ld l, a
|
||
ld h, 1
|
||
ld (literals + 1), hl
|
||
|
||
call read5bits
|
||
inc a
|
||
ld (distances + 1), a
|
||
|
||
call read4bits
|
||
add a, 4
|
||
ld (bt2_cll_cnt + 1), a
|
||
|
||
ld hl, codelengths
|
||
ld b, 20
|
||
xor a
|
||
bt2_clr:
|
||
ld (hl), a
|
||
inc hl
|
||
djnz bt2_clr
|
||
|
||
; DBG: 0xA6 = HLIT/HDIST/HCLEN read OK, reading code length orders
|
||
DBG_OUT #A6
|
||
|
||
ld de, code_length_orders
|
||
ld h, HIGH codelengths
|
||
bt2_cll_cnt EQU $
|
||
ld b, 0
|
||
bt2_cll:
|
||
ld a, (de)
|
||
add a, LOW codelengths
|
||
ld l, a
|
||
call read3bits
|
||
ld (hl), a
|
||
inc de
|
||
djnz bt2_cll
|
||
|
||
; DBG: 0xA9 = code length orders read OK, calling makeHuffmanTable
|
||
DBG_OUT #A9
|
||
|
||
ld bc, 19
|
||
ld hl, codelengths
|
||
ld de, Huffman_Tables_Start
|
||
call makeHuffmanTable
|
||
|
||
; DBG: 0xA7 = first makeHuffmanTable done (proto codes)
|
||
DBG_OUT #A7
|
||
|
||
ld hl, Huffman_Tables_Start
|
||
ld de, codelengths
|
||
literals EQU $
|
||
ld bc, #0000
|
||
ld a, (distances + 1)
|
||
add a, c
|
||
ld c, a
|
||
ld a, b
|
||
adc a, 0
|
||
ld b, a
|
||
call decodeProtoHuffman
|
||
|
||
; DBG: 0xA8 = decodeProtoHuffman done
|
||
DBG_OUT #A8
|
||
|
||
; -- common Huffman table building -------------------------------------------
|
||
huffman_common:
|
||
ld bc, (literals + 1)
|
||
ld hl, codelengths
|
||
ld de, Huffman_Tables_Start
|
||
call makeHuffmanTable
|
||
|
||
ld de, (next_htable_store + 1)
|
||
ld (Dist_HT_Start + 1), de
|
||
|
||
ld hl, codelengths
|
||
ld bc, (literals + 1)
|
||
add hl, bc
|
||
distances EQU $
|
||
ld c, 0
|
||
ld b, 0
|
||
call makeHuffmanTable
|
||
|
||
; Set up decode loop
|
||
interim_dst EQU $
|
||
ld de, #8000
|
||
|
||
Dist_HT_Start EQU $
|
||
ld hl, #0000
|
||
ld a, l
|
||
rra
|
||
rra
|
||
ld l, a
|
||
ld (Dist_HTBegin + 1), hl
|
||
|
||
ld hl, Huffman_Tables_Start
|
||
ld a, l
|
||
rra
|
||
rra
|
||
ld l, a
|
||
ld (HTBegin + 1), hl
|
||
|
||
|
||
; DBG: 0x17 = Huffman tables built, entering decode loop
|
||
DBG_OUT #17
|
||
|
||
; ============================================================================
|
||
; HUFFMAN DECODE LOOP -- unrolled 8x
|
||
; ============================================================================
|
||
decode_tableloop:
|
||
exx
|
||
ld a, b
|
||
exx
|
||
add a, a
|
||
add a, a
|
||
ld (dtl_jr + 1), a
|
||
|
||
HTBegin EQU $
|
||
ld hl, #0000
|
||
ld a, l
|
||
|
||
dtl_jr EQU $
|
||
jr $+2
|
||
jp fail
|
||
nop
|
||
jp decode_tlu_0
|
||
nop
|
||
jp decode_tlu_7
|
||
nop
|
||
jp decode_tlu_6
|
||
nop
|
||
jp decode_tlu_5
|
||
nop
|
||
jp decode_tlu_4
|
||
nop
|
||
jp decode_tlu_3
|
||
nop
|
||
jp decode_tlu_2
|
||
nop
|
||
jp decode_tlu_1
|
||
|
||
HUFFDEC decode_tlu_0, 0, decoded_symbol
|
||
HUFFDEC decode_tlu_1, 1, decoded_symbol
|
||
HUFFDEC decode_tlu_2, 1, decoded_symbol
|
||
HUFFDEC decode_tlu_3, 1, decoded_symbol
|
||
HUFFDEC decode_tlu_4, 1, decoded_symbol
|
||
HUFFDEC decode_tlu_5, 1, decoded_symbol
|
||
HUFFDEC decode_tlu_6, 1, decoded_symbol
|
||
HUFFDEC decode_tlu_7, 1, decoded_symbol
|
||
jp decode_tlu_0
|
||
|
||
|
||
decoded_symbol:
|
||
or a
|
||
jr nz, decode_special
|
||
|
||
inc hl
|
||
ld a, (hl)
|
||
ldi
|
||
|
||
bit 6, d
|
||
jp nz, copy_decoded_page
|
||
jp decode_tableloop
|
||
|
||
|
||
end_of_huffman_block:
|
||
ld (interim_dst + 1), de
|
||
jp END_BLOCK
|
||
|
||
|
||
; -- Length/distance decode ---------------------------------------------------
|
||
decode_special:
|
||
inc hl
|
||
ld a, (hl)
|
||
or a
|
||
jr z, end_of_huffman_block
|
||
|
||
ld hl, lengthcodetable - 4
|
||
add a, a
|
||
add a, a
|
||
add a, l
|
||
ld l, a
|
||
ld a, h
|
||
adc a, 0
|
||
ld h, a
|
||
|
||
ld c, (hl)
|
||
inc hl
|
||
ld b, (hl)
|
||
inc hl
|
||
ld a, (hl)
|
||
inc hl
|
||
ld h, (hl)
|
||
ld l, a
|
||
ld (len_call + 1), hl
|
||
|
||
len_call EQU $
|
||
call #0000
|
||
add a, c
|
||
ld c, a
|
||
ld a, b
|
||
adc a, 0
|
||
ld b, a
|
||
|
||
|
||
; -- Distance decode loop ----------------------------------------------------
|
||
dist_decode_tl:
|
||
exx
|
||
ld a, b
|
||
exx
|
||
add a, a
|
||
add a, a
|
||
ld (ddtl_jr + 1), a
|
||
|
||
Dist_HTBegin EQU $
|
||
ld hl, #0000
|
||
ld a, l
|
||
|
||
ddtl_jr EQU $
|
||
jr $+2
|
||
jp fail
|
||
nop
|
||
jp dist_tlu_0
|
||
nop
|
||
jp dist_tlu_7
|
||
nop
|
||
jp dist_tlu_6
|
||
nop
|
||
jp dist_tlu_5
|
||
nop
|
||
jp dist_tlu_4
|
||
nop
|
||
jp dist_tlu_3
|
||
nop
|
||
jp dist_tlu_2
|
||
nop
|
||
jp dist_tlu_1
|
||
|
||
HUFFDEC dist_tlu_0, 0, dist_sym
|
||
HUFFDEC dist_tlu_1, 1, dist_sym
|
||
HUFFDEC dist_tlu_2, 1, dist_sym
|
||
HUFFDEC dist_tlu_3, 1, dist_sym
|
||
HUFFDEC dist_tlu_4, 1, dist_sym
|
||
HUFFDEC dist_tlu_5, 1, dist_sym
|
||
HUFFDEC dist_tlu_6, 1, dist_sym
|
||
HUFFDEC dist_tlu_7, 1, dist_sym
|
||
jp dist_tlu_0
|
||
|
||
dist_sym:
|
||
inc hl
|
||
ld a, (hl)
|
||
add a, a
|
||
ld l, a
|
||
add a, a
|
||
add a, l
|
||
ld hl, distancecodetable
|
||
add a, l
|
||
ld l, a
|
||
ld a, h
|
||
adc a, 0
|
||
ld h, a
|
||
|
||
push de
|
||
ld e, (hl)
|
||
inc hl
|
||
ld d, (hl)
|
||
inc hl
|
||
push de
|
||
ld e, (hl)
|
||
inc hl
|
||
ld d, (hl)
|
||
inc hl
|
||
ld (dcall1 + 1), de
|
||
ld e, (hl)
|
||
inc hl
|
||
ld d, (hl)
|
||
ld (dcall2 + 1), de
|
||
|
||
dcall1 EQU $
|
||
call #0000
|
||
ld e, a
|
||
dcall2 EQU $
|
||
call #0000
|
||
ld d, a
|
||
|
||
pop hl
|
||
add hl, de
|
||
ex de, hl
|
||
ld hl, 0
|
||
or a
|
||
sbc hl, de
|
||
pop de
|
||
add hl, de ; HL = write_ptr - distance
|
||
|
||
|
||
; ============================================================================
|
||
; BACKREF COPY -- TSConfig paging for history access
|
||
; ============================================================================
|
||
push bc
|
||
dst_page_m2 EQU $
|
||
ld a, 0
|
||
ld bc, PORT_W0
|
||
out (c), a ; Win 0 = dest_page - 2
|
||
inc a
|
||
ld b, HIGH PORT_W1
|
||
out (c), a ; Win 1 = dest_page - 1
|
||
pop bc
|
||
|
||
ldir
|
||
|
||
; Restore Win 0+1 = source pages (BC=0 after LDIR)
|
||
src_page EQU $
|
||
ld a, 0
|
||
OUT_W0
|
||
inc a
|
||
ld b, HIGH PORT_W1 ; C still = #AF from OUT_W0
|
||
out (c), a ; Win 1 = src_page + 1
|
||
|
||
bit 6, d
|
||
jp z, decode_tableloop
|
||
; fall through
|
||
|
||
|
||
; ============================================================================
|
||
; FLUSH DECODE BUFFER to destination page
|
||
; ============================================================================
|
||
copy_decoded_page:
|
||
ld (cpd_extra + 1), de
|
||
|
||
dst_page EQU $
|
||
ld a, 0
|
||
OUT_W0
|
||
|
||
dst EQU $
|
||
ld de, 0
|
||
ld a, e
|
||
or d
|
||
jr z, cpd_whole
|
||
|
||
; Partial page
|
||
ld hl, #4000
|
||
or a
|
||
sbc hl, de
|
||
ld c, l
|
||
ld b, h
|
||
ld l, e
|
||
ld a, d
|
||
or #80
|
||
ld h, a
|
||
ldir
|
||
jr cpd_done
|
||
|
||
cpd_whole:
|
||
ld hl, #8000
|
||
ld de, #0000
|
||
ld bc, #4000
|
||
ldir
|
||
|
||
cpd_done:
|
||
ld hl, 0
|
||
ld (dst + 1), hl
|
||
ld a, (dst_page + 1)
|
||
inc a
|
||
cp #60 ; megabuffer limit (0x20-0x5F)
|
||
jp nc, fail ; overflow → abort
|
||
ld (dst_page + 1), a
|
||
dec a
|
||
dec a
|
||
ld (dst_page_m2 + 1), a
|
||
|
||
; DBG: 0x21 = cpd page flushed
|
||
DBG_OUT_PAGES #21
|
||
|
||
ld de, #8000
|
||
|
||
cpd_extra EQU $
|
||
ld bc, #0000
|
||
ld a, b
|
||
and #3F
|
||
ld b, a
|
||
or c
|
||
jr z, cpd_no_extra
|
||
ld hl, #C000
|
||
ldir
|
||
|
||
cpd_no_extra:
|
||
; Source rollover
|
||
exx
|
||
bit 6, h
|
||
jr z, cpd_no_srcroll
|
||
ld a, h
|
||
and #3F
|
||
ld h, a
|
||
ld a, (src_page + 1)
|
||
inc a
|
||
ld (src_page + 1), a
|
||
cpd_no_srcroll:
|
||
exx
|
||
ld a, (src_page + 1)
|
||
OUT_W0
|
||
inc a
|
||
ld b, HIGH PORT_W1 ; C still = #AF from OUT_W0
|
||
out (c), a ; Win 1 = src_page + 1
|
||
push de ; save decode write ptr (DE clobbered by progress_update)
|
||
call progress_update
|
||
pop de ; restore decode write ptr
|
||
jp decode_tableloop
|
||
|
||
|
||
; ============================================================================
|
||
; END_BLOCK -- last block check, final flush, exit
|
||
; ============================================================================
|
||
END_BLOCK:
|
||
this_was_last_block EQU $
|
||
ld a, 0
|
||
or a
|
||
jp z, NEW_BLOCK
|
||
|
||
; Final flush
|
||
ld a, (dst_page + 1)
|
||
OUT_W0
|
||
ld de, (dst + 1)
|
||
ld hl, (interim_dst + 1)
|
||
or a
|
||
sbc hl, de
|
||
ld c, l
|
||
ld a, h
|
||
and #3F
|
||
ld b, a
|
||
or c
|
||
jr z, exit_ok
|
||
ld l, e
|
||
ld a, d
|
||
and #3F
|
||
ld d, a
|
||
or #80
|
||
ld h, a
|
||
ldir
|
||
|
||
exit_ok:
|
||
; DBG: 0x30 = exit_ok
|
||
DBG_OUT_PAGES #30
|
||
|
||
wc_saved_pg2 EQU $
|
||
ld a, 0
|
||
OUT_W2
|
||
xor a
|
||
ret
|
||
|
||
fail:
|
||
; DBG: 0x31 = fail
|
||
DBG_OUT #31
|
||
|
||
ld a, (wc_saved_pg2 + 1)
|
||
OUT_W2
|
||
ld a, 1
|
||
scf
|
||
ret
|
||
|
||
|
||
; ============================================================================
|
||
; PROGRESS BAR UPDATE (Bresenham proportional column fill)
|
||
;
|
||
; Called after each output page flush (from copy_decoded_page and bt0 flush).
|
||
; Briefly remaps Win 0 to the text screen page, writes green attr bytes
|
||
; to fill the progress bar proportionally, restores Win 0 to source page.
|
||
;
|
||
; Destroys: A, BC, DE, HL. Alternate registers untouched.
|
||
; Parameters in pb_* block at 0xC1F0 (set by inflate_call.s before entry).
|
||
; ============================================================================
|
||
progress_update:
|
||
ld a, (pb_total)
|
||
or a
|
||
ret z ; 0 = disabled
|
||
|
||
; Bar already full?
|
||
ld a, (pb_col)
|
||
ld hl, pb_bar_w
|
||
cp (hl)
|
||
ret nc ; col >= width → done
|
||
|
||
; Bresenham: error += bar_width
|
||
ld a, (pb_error)
|
||
add a, (hl) ; (hl) still = pb_bar_w
|
||
ld d, a ; D = new error
|
||
|
||
; E = total
|
||
ld a, (pb_total)
|
||
ld e, a
|
||
|
||
; error < total → no column this time
|
||
ld a, d
|
||
cp e
|
||
jr c, pb_save_err ; skip fill, just save error
|
||
|
||
; ═══ At least one column to fill ═══
|
||
; Map Win 0 → text screen page
|
||
ld a, (pb_text_pg)
|
||
OUT_W0 ; destroys BC
|
||
|
||
; HL = attr base address (bit7 of L is already set)
|
||
ld a, (pb_attr_hi)
|
||
ld h, a
|
||
ld a, (pb_attr_lo)
|
||
ld l, a
|
||
ld a, (pb_col)
|
||
add a, l
|
||
ld l, a ; attr area: stride 1, no overflow
|
||
; C = green attr value, B = bar width limit
|
||
ld a, (pb_green)
|
||
ld c, a
|
||
ld a, (pb_bar_w)
|
||
ld b, a
|
||
|
||
pb_fill_loop:
|
||
ld (hl), c ; write green attr
|
||
inc l ; next column (stride 1, same row)
|
||
|
||
; pb_col++
|
||
ld a, (pb_col)
|
||
inc a
|
||
ld (pb_col), a
|
||
cp b ; col >= bar_width?
|
||
jr nc, pb_fill_done
|
||
|
||
; error -= total
|
||
ld a, d
|
||
sub e
|
||
ld d, a
|
||
cp e ; still >= total?
|
||
jr nc, pb_fill_loop
|
||
|
||
pb_fill_done:
|
||
; Restore Win 0 → source page
|
||
ld a, (src_page + 1)
|
||
OUT_W0 ; destroys BC
|
||
|
||
pb_save_err:
|
||
ld a, d
|
||
ld (pb_error), a
|
||
ret
|
||
|
||
|
||
; ============================================================================
|
||
; GZIP HEADER SKIP ROUTINES
|
||
; ============================================================================
|
||
drop_gz_fextra:
|
||
push hl
|
||
push bc
|
||
call read8bits
|
||
ld l, a
|
||
call read8bits
|
||
ld h, a
|
||
or c
|
||
jp z, fextra_ret
|
||
ld bc, 255
|
||
fextra_lp:
|
||
ld a, h
|
||
or a
|
||
jr z, fextra_last
|
||
ld a, 255
|
||
call dropbytes
|
||
or a
|
||
sbc hl, bc
|
||
jr fextra_lp
|
||
fextra_last:
|
||
ld a, l
|
||
call dropbytes
|
||
fextra_ret:
|
||
pop bc
|
||
pop hl
|
||
ret
|
||
|
||
drop_gz_fname:
|
||
drop_gz_fcomment:
|
||
call read8bits
|
||
or a
|
||
jr nz, drop_gz_fname
|
||
ret
|
||
|
||
drop_gz_fhcrc:
|
||
ld a, 2
|
||
call dropbytes
|
||
ret
|
||
|
||
|
||
; ============================================================================
|
||
; UTILITY
|
||
; ============================================================================
|
||
dropbytes:
|
||
or a
|
||
ret z
|
||
push bc
|
||
ld b, a
|
||
db_lp: call read8bits
|
||
djnz db_lp
|
||
pop bc
|
||
ret
|
||
|
||
|
||
; ============================================================================
|
||
; makeHuffmanTable
|
||
; ============================================================================
|
||
makeHuffmanTable:
|
||
ld (mht_nsym + 1), bc
|
||
ld (mht_clens + 1), hl
|
||
ld (mht_tstore + 1), de
|
||
|
||
ld hl, codelength_count
|
||
ld b, 18
|
||
mht_clr:
|
||
ld (hl), 0
|
||
inc hl
|
||
ld (hl), 0
|
||
inc hl
|
||
djnz mht_clr
|
||
|
||
mht_nsym EQU $
|
||
ld bc, #0000
|
||
mht_clens EQU $
|
||
ld hl, #0000
|
||
ld de, codelength_count
|
||
|
||
mht_cnt:
|
||
ld a, (hl)
|
||
inc hl
|
||
add a, a
|
||
ld e, a
|
||
ld a, (de)
|
||
inc a
|
||
ld (de), a
|
||
or a
|
||
jr nz, mht_cnt_ok
|
||
inc de
|
||
ld a, (de)
|
||
inc a
|
||
ld (de), a
|
||
mht_cnt_ok:
|
||
dec bc
|
||
ld a, b
|
||
or c
|
||
jr nz, mht_cnt
|
||
|
||
; DBG: 0xB1 = mht_cnt done (count loop)
|
||
DBG_OUT #B1
|
||
|
||
xor a
|
||
ld e, a
|
||
ld (de), a
|
||
inc de
|
||
ld (de), a
|
||
|
||
ld e, a
|
||
ld d, a
|
||
ld c, a
|
||
ld b, 1
|
||
mht_sc:
|
||
ld h, HIGH codelength_count
|
||
ld a, b
|
||
dec a
|
||
add a, a
|
||
ld l, a
|
||
ld a, (hl)
|
||
add a, e
|
||
ld e, a
|
||
inc hl
|
||
ld a, (hl)
|
||
adc a, d
|
||
ld d, a
|
||
ld a, c
|
||
adc a, 0
|
||
ld c, a
|
||
rl e
|
||
rl d
|
||
rl c
|
||
ld h, HIGH next_code
|
||
ld a, b
|
||
rla
|
||
rla
|
||
ld l, a
|
||
ld (hl), e
|
||
inc hl
|
||
ld (hl), d
|
||
inc hl
|
||
ld (hl), c
|
||
inc hl
|
||
ld (hl), 0
|
||
inc b
|
||
ld a, b
|
||
cp 19
|
||
jr c, mht_sc
|
||
|
||
; DBG: 0xB2 = mht_sc done (start codes)
|
||
DBG_OUT #B2
|
||
|
||
ld bc, 0
|
||
mht_assign:
|
||
ld hl, (mht_clens + 1)
|
||
add hl, bc
|
||
ld a, (hl)
|
||
or a
|
||
jr z, mht_nocode
|
||
|
||
rla
|
||
rla
|
||
ld l, a
|
||
ld h, HIGH next_code
|
||
push hl
|
||
ld e, (hl)
|
||
inc hl
|
||
ld d, (hl)
|
||
inc hl
|
||
ld a, (hl)
|
||
|
||
ld hl, codes
|
||
add hl, bc
|
||
add hl, bc
|
||
add hl, bc
|
||
add hl, bc
|
||
ld (hl), e
|
||
inc hl
|
||
ld (hl), d
|
||
inc hl
|
||
ld (hl), a
|
||
|
||
pop hl
|
||
inc e
|
||
ld (hl), e
|
||
inc hl
|
||
ld e, a
|
||
ld a, d
|
||
adc a, 0
|
||
ld (hl), a
|
||
inc hl
|
||
ld a, e
|
||
adc a, 0
|
||
ld (hl), a
|
||
|
||
mht_nocode:
|
||
inc bc
|
||
ld hl, (mht_nsym + 1)
|
||
or a
|
||
sbc hl, bc
|
||
jr nz, mht_assign
|
||
|
||
; DBG: 0xB3 = mht_assign done (code assignment)
|
||
DBG_OUT #B3
|
||
|
||
; Build lookup tables
|
||
ld hl, (mht_tstore + 1)
|
||
xor a
|
||
ld (hl), a
|
||
inc hl
|
||
ld (hl), a
|
||
inc hl
|
||
ld (hl), a
|
||
inc hl
|
||
ld (hl), a
|
||
inc hl
|
||
ld (next_htable_store + 1), hl
|
||
|
||
ld hl, 0
|
||
ld (mht_tabulated + 1), hl
|
||
ld de, (mht_tabulated + 1)
|
||
|
||
mht_predec:
|
||
ld hl, (mht_clens + 1)
|
||
add hl, de
|
||
ld a, (hl)
|
||
or a
|
||
jp z, mht_unused
|
||
ld b, a
|
||
|
||
ld hl, codes
|
||
add hl, de
|
||
add hl, de
|
||
add hl, de
|
||
add hl, de
|
||
ld d, (hl)
|
||
inc hl
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, (hl)
|
||
rra
|
||
rr c
|
||
rr d
|
||
rra
|
||
rr c
|
||
rr d
|
||
rra
|
||
ld e, a
|
||
|
||
ld a, 18
|
||
sub b
|
||
jr z, mht_nodiscard
|
||
or a
|
||
mht_discard:
|
||
rl e
|
||
rl d
|
||
rl c
|
||
dec a
|
||
jr nz, mht_discard
|
||
mht_nodiscard:
|
||
|
||
mht_tstore EQU $
|
||
ld hl, #0000
|
||
|
||
mht_nextbit:
|
||
rl e
|
||
rl d
|
||
rl c
|
||
jr nc, mht_bitzero
|
||
inc hl
|
||
inc hl
|
||
mht_bitzero:
|
||
dec b
|
||
jr z, mht_wrsym
|
||
|
||
ld a, (hl)
|
||
or a
|
||
jr z, mht_wrtable
|
||
|
||
inc hl
|
||
ld h, (hl)
|
||
add a, a
|
||
add a, a
|
||
ld l, a
|
||
jr mht_nextbit
|
||
|
||
mht_wrtable:
|
||
push de
|
||
next_htable_store EQU $
|
||
ld de, #0000
|
||
ld a, e
|
||
rra
|
||
scf
|
||
rra
|
||
ld (hl), a
|
||
inc hl
|
||
ld (hl), d
|
||
ld l, e
|
||
ld h, d
|
||
xor a
|
||
ld (de), a
|
||
inc de
|
||
ld (de), a
|
||
inc de
|
||
ld (de), a
|
||
inc de
|
||
ld (de), a
|
||
inc de
|
||
ld (next_htable_store + 1), de
|
||
pop de
|
||
jr mht_nextbit
|
||
|
||
mht_wrsym:
|
||
mht_tabulated EQU $
|
||
ld de, #0000
|
||
ld (hl), d
|
||
inc hl
|
||
ld (hl), e
|
||
|
||
mht_unused:
|
||
inc de
|
||
ld (mht_tabulated + 1), de
|
||
ld hl, (mht_nsym + 1)
|
||
or a
|
||
sbc hl, de
|
||
ld a, h
|
||
or l
|
||
jp nz, mht_predec
|
||
ret
|
||
|
||
|
||
; ============================================================================
|
||
; decodeProtoHuffman
|
||
; ============================================================================
|
||
decodeProtoHuffman:
|
||
ld a, l
|
||
rra
|
||
rra
|
||
ld l, a
|
||
ld (dph_begin + 1), hl
|
||
IFDEF DBG_ENABLE
|
||
; DBG: 0xBF = decodeProtoHuffman entry
|
||
push af
|
||
push bc
|
||
ld a, #BF
|
||
ld bc, DBG_STATUS
|
||
out (c), a
|
||
pop bc
|
||
pop af
|
||
ENDIF
|
||
jr dph_jump
|
||
|
||
dph_tloop:
|
||
inc hl
|
||
ld h, (hl)
|
||
ld l, a
|
||
dph_jump:
|
||
call read1bit
|
||
rra
|
||
ld a, l
|
||
adc a, a
|
||
add a, a
|
||
ld l, a
|
||
ld a, (hl)
|
||
bit 7, a
|
||
jr nz, dph_tloop
|
||
inc hl
|
||
ld a, (hl)
|
||
IFDEF DBG_ENABLE
|
||
; DBG: 0xC1 = leaf found, FEAF = symbol value
|
||
push af
|
||
push bc
|
||
ld bc, DBG_SRC
|
||
out (c), a
|
||
ld a, #C1
|
||
ld bc, DBG_STATUS
|
||
out (c), a
|
||
pop bc
|
||
pop af
|
||
ENDIF
|
||
cp 16
|
||
jr nc, dph_special
|
||
ld (de), a
|
||
inc de
|
||
dec bc
|
||
dph_loop:
|
||
IFDEF DBG_ENABLE
|
||
; DBG: 0xC0 = dph loop iteration
|
||
push af
|
||
push bc
|
||
ld a, #C0
|
||
ld bc, DBG_STATUS
|
||
out (c), a
|
||
pop bc
|
||
pop af
|
||
ENDIF
|
||
dph_begin EQU $
|
||
ld hl, #0000
|
||
ld a, b
|
||
or c
|
||
jr nz, dph_jump
|
||
ret
|
||
|
||
dph_special:
|
||
IFDEF DBG_ENABLE
|
||
; DBG: 0xC2 = special code, FEAF = code value
|
||
push af
|
||
push bc
|
||
ld bc, DBG_SRC
|
||
out (c), a
|
||
ld a, #C2
|
||
ld bc, DBG_STATUS
|
||
out (c), a
|
||
pop bc
|
||
pop af
|
||
ENDIF
|
||
cp 17
|
||
jr z, dph_17
|
||
jr nc, dph_18
|
||
; proto 16
|
||
call read2bits
|
||
add a, 3
|
||
ld h, a
|
||
dec de
|
||
ld a, (de)
|
||
inc de
|
||
dph_p16:
|
||
ld (de), a
|
||
inc de
|
||
dec bc
|
||
dec h
|
||
jr nz, dph_p16
|
||
jr dph_loop
|
||
|
||
dph_17:
|
||
call read3bits
|
||
add a, 3
|
||
ld h, a
|
||
xor a
|
||
dph_p17:
|
||
ld (de), a
|
||
inc de
|
||
dec bc
|
||
dec h
|
||
jr nz, dph_p17
|
||
jr dph_loop
|
||
|
||
dph_18:
|
||
call read7bits
|
||
add a, 11
|
||
ld h, a
|
||
xor a
|
||
dph_p18:
|
||
ld (de), a
|
||
inc de
|
||
dec bc
|
||
dec h
|
||
jr nz, dph_p18
|
||
jr dph_loop
|
||
|
||
|
||
; ============================================================================
|
||
; BIT READ FUNCTIONS
|
||
; Alternate regs: HL'=src ptr, C'=current byte, B'=valid bits
|
||
; ============================================================================
|
||
|
||
read0bits:
|
||
xor a
|
||
ret
|
||
|
||
read1bit:
|
||
read1bits:
|
||
exx
|
||
dec b
|
||
jr z, r1_refill
|
||
xor a
|
||
rr c
|
||
rla
|
||
exx
|
||
ret
|
||
r1_refill:
|
||
xor a
|
||
rr c
|
||
rla
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
|
||
; -- read2bits ---------------------------------------------------------------
|
||
read2bits:
|
||
exx
|
||
ld a, b
|
||
sub 2
|
||
jr c, r2_need
|
||
jr z, r2_exact
|
||
ld b, a
|
||
ld e, c
|
||
ld a, c
|
||
rra
|
||
rra
|
||
and #3F
|
||
ld c, a
|
||
ld a, e
|
||
and #03
|
||
exx
|
||
ret
|
||
r2_exact:
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r2_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r2_sl: add a, a
|
||
djnz r2_sl
|
||
or e
|
||
and #03
|
||
ld e, a
|
||
ld a, 2
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r2_sr: or a
|
||
rra
|
||
djnz r2_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 2
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; -- read3bits ---------------------------------------------------------------
|
||
read3bits:
|
||
exx
|
||
ld a, b
|
||
sub 3
|
||
jr c, r3_need
|
||
jr z, r3_exact
|
||
ld b, a
|
||
ld e, c
|
||
ld a, c
|
||
rra
|
||
rra
|
||
rra
|
||
and #1F
|
||
ld c, a
|
||
ld a, e
|
||
and #07
|
||
exx
|
||
ret
|
||
r3_exact:
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r3_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r3_sl: add a, a
|
||
djnz r3_sl
|
||
or e
|
||
and #07
|
||
ld e, a
|
||
ld a, 3
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r3_sr: or a
|
||
rra
|
||
djnz r3_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 3
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; -- read4bits ---------------------------------------------------------------
|
||
read4bits:
|
||
exx
|
||
ld a, b
|
||
sub 4
|
||
jr c, r4_need
|
||
jr z, r4_exact
|
||
ld b, a
|
||
ld e, c
|
||
ld a, c
|
||
rra
|
||
rra
|
||
rra
|
||
rra
|
||
and #0F
|
||
ld c, a
|
||
ld a, e
|
||
and #0F
|
||
exx
|
||
ret
|
||
r4_exact:
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r4_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r4_sl: add a, a
|
||
djnz r4_sl
|
||
or e
|
||
and #0F
|
||
ld e, a
|
||
ld a, 4
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r4_sr: or a
|
||
rra
|
||
djnz r4_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 4
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; -- read5bits ---------------------------------------------------------------
|
||
read5bits:
|
||
exx
|
||
ld a, b
|
||
sub 5
|
||
jr c, r5_need
|
||
jr z, r5_exact
|
||
ld b, a
|
||
ld e, c
|
||
ld a, c
|
||
rlca
|
||
rlca
|
||
rlca
|
||
and #07
|
||
ld c, a
|
||
ld a, e
|
||
and #1F
|
||
exx
|
||
ret
|
||
r5_exact:
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r5_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r5_sl: add a, a
|
||
djnz r5_sl
|
||
or e
|
||
and #1F
|
||
ld e, a
|
||
ld a, 5
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r5_sr: or a
|
||
rra
|
||
djnz r5_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 5
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; -- read6bits ---------------------------------------------------------------
|
||
read6bits:
|
||
exx
|
||
ld a, b
|
||
sub 6
|
||
jr c, r6_need
|
||
jr z, r6_exact
|
||
ld b, a
|
||
ld e, c
|
||
ld a, c
|
||
rlca
|
||
rlca
|
||
and #03
|
||
ld c, a
|
||
ld a, e
|
||
and #3F
|
||
exx
|
||
ret
|
||
r6_exact:
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r6_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r6_sl: add a, a
|
||
djnz r6_sl
|
||
or e
|
||
and #3F
|
||
ld e, a
|
||
ld a, 6
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r6_sr: or a
|
||
rra
|
||
djnz r6_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 6
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; -- read7bits ---------------------------------------------------------------
|
||
read7bits:
|
||
exx
|
||
ld a, b
|
||
sub 7
|
||
jr c, r7_need
|
||
jr z, r7_exact
|
||
ld b, a
|
||
ld e, c
|
||
ld a, c
|
||
rlca
|
||
and #01
|
||
ld c, a
|
||
ld a, e
|
||
and #7F
|
||
exx
|
||
ret
|
||
r7_exact:
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r7_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r7_sl: add a, a
|
||
djnz r7_sl
|
||
or e
|
||
and #7F
|
||
ld e, a
|
||
ld a, 7
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r7_sr: or a
|
||
rra
|
||
djnz r7_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 7
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; -- read8bits ---------------------------------------------------------------
|
||
read8bits:
|
||
exx
|
||
ld a, b
|
||
sub 8
|
||
jr c, r8_need
|
||
; b was 8 (exact)
|
||
ld a, c
|
||
ld b, 8
|
||
ld c, (hl)
|
||
inc hl
|
||
exx
|
||
ret
|
||
r8_need:
|
||
ld e, c
|
||
ld d, b
|
||
ld c, (hl)
|
||
inc hl
|
||
ld a, c
|
||
r8_sl: add a, a
|
||
djnz r8_sl
|
||
or e
|
||
ld e, a
|
||
ld a, 8
|
||
sub d
|
||
ld b, a
|
||
ld a, c
|
||
r8_sr: or a
|
||
rra
|
||
djnz r8_sr
|
||
ld c, a
|
||
ld a, d
|
||
sub 8
|
||
add a, 8
|
||
ld b, a
|
||
ld a, e
|
||
exx
|
||
ret
|
||
|
||
; Byte-align
|
||
readalign:
|
||
exx
|
||
ld c, (hl)
|
||
inc hl
|
||
ld b, 8
|
||
exx
|
||
ret
|
||
|
||
|
||
; ============================================================================
|
||
; DATA TABLES
|
||
; ============================================================================
|
||
|
||
lengthcodetable:
|
||
DW 3, read0bits
|
||
DW 4, read0bits
|
||
DW 5, read0bits
|
||
DW 6, read0bits
|
||
DW 7, read0bits
|
||
DW 8, read0bits
|
||
DW 9, read0bits
|
||
DW 10, read0bits
|
||
DW 11, read1bits
|
||
DW 13, read1bits
|
||
DW 15, read1bits
|
||
DW 17, read1bits
|
||
DW 19, read2bits
|
||
DW 23, read2bits
|
||
DW 27, read2bits
|
||
DW 31, read2bits
|
||
DW 35, read3bits
|
||
DW 43, read3bits
|
||
DW 51, read3bits
|
||
DW 59, read3bits
|
||
DW 67, read4bits
|
||
DW 83, read4bits
|
||
DW 99, read4bits
|
||
DW 115, read4bits
|
||
DW 131, read5bits
|
||
DW 163, read5bits
|
||
DW 195, read5bits
|
||
DW 227, read5bits
|
||
DW 258, read0bits
|
||
|
||
distancecodetable:
|
||
DW 1, read0bits, read0bits
|
||
DW 2, read0bits, read0bits
|
||
DW 3, read0bits, read0bits
|
||
DW 4, read0bits, read0bits
|
||
DW 5, read1bits, read0bits
|
||
DW 7, read1bits, read0bits
|
||
DW 9, read2bits, read0bits
|
||
DW 13, read2bits, read0bits
|
||
DW 17, read3bits, read0bits
|
||
DW 25, read3bits, read0bits
|
||
DW 33, read4bits, read0bits
|
||
DW 49, read4bits, read0bits
|
||
DW 65, read5bits, read0bits
|
||
DW 97, read5bits, read0bits
|
||
DW 129, read6bits, read0bits
|
||
DW 193, read6bits, read0bits
|
||
DW 257, read7bits, read0bits
|
||
DW 385, read7bits, read0bits
|
||
DW 513, read8bits, read0bits
|
||
DW 769, read8bits, read0bits
|
||
DW 1025, read8bits, read1bits
|
||
DW 1537, read8bits, read1bits
|
||
DW 2049, read8bits, read2bits
|
||
DW 3073, read8bits, read2bits
|
||
DW 4097, read8bits, read3bits
|
||
DW 6145, read8bits, read3bits
|
||
DW 8193, read8bits, read4bits
|
||
DW 12289, read8bits, read4bits
|
||
DW 16385, read8bits, read5bits
|
||
DW 24577, read8bits, read5bits
|
||
|
||
code_length_orders:
|
||
DB 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||
|
||
DB "tsconf-inflate", 0
|
||
|
||
DISPLAY "Code size: ", /D, $ - #C000, " bytes"
|
||
|
||
|
||
; ============================================================================
|
||
; RAM TABLES (zero-initialized)
|
||
; ============================================================================
|
||
|
||
ALIGN 256
|
||
codelength_count:
|
||
DS 36
|
||
|
||
ALIGN 32
|
||
codelengths:
|
||
DS 288 + 33
|
||
|
||
ALIGN 256
|
||
next_code:
|
||
DS 128
|
||
|
||
ALIGN 256
|
||
codes:
|
||
DS 288 * 4
|
||
|
||
ALIGN 4
|
||
Huffman_Tables_Start:
|
||
|
||
DISPLAY "Huffman space: ", /D, #FFFE - Huffman_Tables_Start + 2, " bytes"
|
||
|
||
SAVEBIN "build/inflate.bin", #C000, $ - #C000
|