; LZSS decoder for SEGA Master System / Game Gear ; /Mic, 2009 ; The decoder function itself is 191 bytes in size ; Note: The base address must be $C000 for the address masking in the decoder to work. .DEFINE LZSS_RAM_BASE $C000 .DEFINE LZSS_TEXTBUF LZSS_RAM_BASE .DEFINE LZSS_CNT LZSS_RAM_BASE+LZSS_DICTIONARY_SIZE .DEFINE LZSS_PTR LZSS_CNT+2 .DEFINE LZSS_CNT2 LZSS_PTR+2 .DEFINE LZSS_BITPLANES LZSS_CNT2+1 .DEFINE LZSS_PLANECNT LZSS_CNT2+2 .DEFINE LZSS_FLAGS LZSS_CNT2+3 .DEFINE LZSS_TEXTBUF_P (LZSS_DICTIONARY_SIZE-LZSS_MAX_LEN) ; Function lzss_decode_vram ; ; Decompress LZSS packed data to VRAM ; ; In: ; IX = Pointer to compressed data ; IY = Size of compressed data ; HL = VRAM base address ; ; Out: ; - ; ; Example: ; ; ld ix,packed_patterns ; ld iy,packed_patterns_end-packed_patterns ; ld hl,$2000 ; call lzss_decode_vram ; lzss_decode_vram: ; Set the VRAM address ld a,l out ($BF),a ld a,h or $40 out ($BF),a ld hl,LZSS_TEXTBUF+LZSS_TEXTBUF_P ld (LZSS_PTR),hl ; Set all entries in textbuf to 0 ld hl,LZSS_TEXTBUF ld bc,LZSS_TEXTBUF_P _ldv_init_textbuf: ld a,0 ld (hl),a inc hl dec bc ld a,b or c jr nz,_ldv_init_textbuf ld a,0 ld (LZSS_PLANECNT),a _ldv_loop: ld a,iyl or iyh ; Do we have any more bytes remaining? jp z,_ldv_done ld a,(ix+0) ; Read one compressed byte dec iy inc ix ; Increase input stream pointer ld (LZSS_FLAGS),a ld a,8 ; 8 flags per byte ld (LZSS_CNT2),a _ldv_check_flags: ld a,(LZSS_PLANECNT) ld c,a ld a,(LZSS_FLAGS) srl a ld (LZSS_FLAGS),a jr nc,_ldv_flag_clear ld a,iyl or iyh jr z,_ldv_done ld a,(ix+0) ; Read one compressed byte dec iy inc ix ld b,1 ; Make sure the jr after output_byte isn't taken ld hl,(LZSS_PTR) jr _ldv_output_byte _ldv_flag_clear: ld a,iyl or iyh jr z,_ldv_done ld e,(ix+0) ; e = idx inc ix ld a,(ix+0) ; a = j inc ix dec iy dec iy ld d,a .REPT LZSS_LEN_BITS srl d ; de = ((j & 0xF0) << 4) | idx .ENDR and LZSS_LEN_MASK add a,LZSS_THRESHOLD+1 ld b,a ; b = (j & 0x0F) + THRESHOLD ld a,d or >(LZSS_RAM_BASE) ; de |= $C000 ld d,a ld hl,(LZSS_PTR) _ldv_copy_string: ld a,(de) ; Read from textbuf push af ; Increase read address and wrap inc de ld a,d and >(LZSS_RAM_BASE+LZSS_DICTIONARY_SIZE-1) ld d,a pop af _ldv_output_byte: out ($BE),a ; Write to VRAM ld (hl),a ; Write to textbuf .IF LZSS_PLANES_USED < LZSS_FORMAT_PLANES ; Pad with empty bitplanes if needed ld a,c inc a and LZSS_FORMAT_PLANES-1 ld c,a ld a,LZSS_PLANES_USED-1 cp c jr nc,_ldv_dont_pad _ldv_pad: ld a,0 out ($BE),a inc c ld a,c and LZSS_FORMAT_PLANES-1 jr nz,_ldv_pad _ldv_dont_pad: .ENDIF ; Increase write address and wrap inc hl ld a,h and >(LZSS_RAM_BASE+LZSS_DICTIONARY_SIZE-1) ld h,a _ldv_next_string_pos: dec b jr nz,_ldv_copy_string ld a,c ld (LZSS_PLANECNT),a ld (LZSS_PTR),hl _ldv_next_flag: ld a,(LZSS_CNT2) dec a ld (LZSS_CNT2),a jp z,_ldv_loop jp _ldv_check_flags _ldv_done: ret