# LZSS decoder for SEGA Megadrive (Genesis) # /Mic, 2009 .IFNDEF LZSS_DICTIONARY_SIZE .EQU LZSS_DICTIONARY_SIZE, 4096 .ENDIF .IFNDEF LZSS_THRESHOLD .EQU LZSS_THRESHOLD, 2 .ENDIF .IFNDEF LZSS_LEN_BITS .EQU LZSS_LEN_BITS, 4 .ENDIF .IFNDEF LZSS_LEN_MASK .EQU LZSS_LEN_MASK, 0x0f .ENDIF .IFNDEF LZSS_MAX_LEN .EQU LZSS_MAX_LEN, 18 .ENDIF .IFNDEF LZSS_RAM_BASE .EQU LZSS_RAM_BASE, 0xffff8000 .ENDIF .EQU LZSS_TEXTBUF, LZSS_RAM_BASE .EQU LZSS_CNT, (LZSS_RAM_BASE+LZSS_DICTIONARY_SIZE) .EQU LZSS_TEXTBUF_P, (LZSS_DICTIONARY_SIZE-LZSS_MAX_LEN) .TEXT .ALIGN 1 .GLOBAL lzss_decode_vram # Function lzss_decode_vram # # Decompress LZSS packed data to VRAM # # In: # # D0 = Size of compressed data # A2 = Pointer to compressed data # A3 = VRAM base address # # Out: # - # # Example: # # move.l #(packed_patterns_end-packed_patterns),d0 # move.l #packed_patterns,a2 # move.l #0x2000,a3 # jsr lzss_decode_vram # lzss_decode_vram: .IF 1 .IFNDEF LZSS_DECODE_RAM # Set the VRAM address move.l a3,d6 move.l a3,d7 and.w #0x3fff,d6 lsr.w #7,d7 lsr.w #7,d7 add.w #0x4000,d6 lsl.l #7,d6 lsl.l #7,d6 lsl.l #2,d6 or.l d7,d6 move.l d6,0xC00004 move.l #0xC00000,a1 moveq.l #0,d7 moveq.l #0,d4 .ENDIF # Set all entries in textbuf to 0 move.l #LZSS_TEXTBUF,a3 move.w #LZSS_TEXTBUF_P-1,d1 _ldv_init_textbuf: move.b #0,(a3)+ dbra d1,_ldv_init_textbuf _ldv_loop: or.l d0,d0 beq.s _ldv_done move.b (a2)+,d2 /* d2 = flags */ subq.l #1,d0 moveq.l #7,d3 /* d3 = flag count */ _ldv_check_flags: lsr.b #1,d2 bcc.s _ldv_flag_clear or.l d0,d0 beq.s _ldv_done move.b (a2)+,d6 subq.l #1,d0 moveq.l #0,d5 bra.s _ldv_output_byte _ldv_flag_clear: or.l d0,d0 beq.s _ldv_done move.b (a2)+,d1 /* d1 = idx */ move.b (a2)+,d5 /* d5 = j */ subq.l #2,d0 and.w #0xFF,d5 move.l d5,d6 lsr.b #LZSS_LEN_BITS,d6 lsl.w #8,d6 or.b d1,d6 /* d6 = ((j & 0xF0) << 4) | idx */ and.b #LZSS_LEN_MASK,d5 add.w #LZSS_THRESHOLD,d5 or.l #LZSS_RAM_BASE,d6 move.l d6,a4 _ldv_copy_string: move.b (a4)+,d6 move.l a4,d1 and.w #((LZSS_RAM_BASE & 0xFFFF)+LZSS_DICTIONARY_SIZE-1),d1 move.l d1,a4 _ldv_output_byte: move.b d6,(a3)+ /* Write to TEXTBUF */ .IFDEF LZSS_DECODE_RAM move.b d6,(a1)+ .ELSE btst.b #0,d7 beq.s _ldv_no_vram_write lsl.w #8,d4 or.b d6,d4 move.w d4,(a1) /* Write to VRAM */ bra.s _ldv_wrap_adr _ldv_no_vram_write: move.l d6,d4 .ENDIF _ldv_wrap_adr: eor.b #1,d7 # Increase write address and wrap move.l a3,d1 and.w #((LZSS_RAM_BASE & 0xFFFF)+LZSS_DICTIONARY_SIZE-1),d1 move.l d1,a3 _ldv_next_string_pos: dbra d5,_ldv_copy_string _ldv_next_flag: dbra d3,_ldv_check_flags bra.s _ldv_loop _ldv_done: rts .ENDIF