; dan0alt.s
;-----------------------------------------------------------
; DAN0 Alternative VRAM Depacker v1.0 by Daniel Bienvenu, March 2010.
; Compiled version : 101 bytes
;-----------------------------------------------------------
; USAGE : dan0alt(vram_offset, tblcodes);
;         tblcodes = *tbldata, RLE & Huffman codes
;         tbldata = bytes to output
;         vram_offset = address in VRAM
;-----------------------------------------------------------
; RLE codes
; =========
; 00h = 256 bytes to output
; 01h-7Fh = 1 to 127 bytes to output
; 80h = 256 times 1 byte to output
; 81h = END
; 82h-FFh = 2 to 127 times 1 byte to output
;-----------------------------------------------------------
; BIT codes ( fixed Huffman table )
; =======================================
; [0] = get next byte in tbldata   
; [100] = get 1st previous byte     
; [110] = get 2nd previous byte     
; [10100] = get 3rd previous byte  
; [10101] = get 4th previous byte  
; [10110] = get 5th previous byte  
; [10111] = get 6th previous byte  
; [11100] = get 7th previous byte  
; [11101] = get 8th previous byte  
; [11110] = get 9th previous byte 
; [11111] = get 10th previous byte
;-----------------------------------------------------------

    .module dan0

    .globl  _dan0alt, dan0alt
    ; void dan0 (unsigned vram_offset, void *tblcodes);

    .area _CODE

_dan0alt:

    pop bc
    pop hl
    pop de
    push de
    push hl
    push bc
    
;; ASM routine entry point
;; IN : HL = VRAM OFFSET
;;       DE = CONTROL POINTER - 2 ( for the DATA_TABLE pointer stored first )
;; OUT : DE = POINTER TO AFTER THE END OF CONTROL_TABLE
;;            HL = POINTER TO AFTER THE END OF DATA_TABLE
;;            C = I/O PORT ( = #0xbe)
;;            AF, AF', B = GARBAGE

dan0alt:
    ; OFFSET VRAM
    ld  c,#0xbf
      
    out (c),l
    set 6,h
    out (c),h
    
    ; GET DATA_TABLE POINTER
    ex de,hl     
    ld e,(hl)
    inc hl
    ld d,(hl)
    inc hl
    ex de,hl
    dec c ;ld c,#0xbe
    
    ; DE = CTRL_TABLE POINTER
    ; HL = DATA_TABLE POINTER
    ; C = I/O PORT
    
    ld a,#0x80
    ex af,af'
    
    ;;  A' = 0x80
    ;;  C = 0xBE
    ;;  Z FLAG PUSHED
    
dan0_main:
    ld a,(de)
    inc de
    bit 7,a
    jr z, dan0_raw
    and #0x7f
    ld b,a
    sub a,#1
    ret z ; EXIT POINT
    call dan0_readnextbyte
    
dan0_rle_loop:
    out (c),a
    djnz dan0_rle_loop
    jr dan0_main
    
dan0_raw:
    ld b,a
    
dan0_raw_loop:
    call dan0_readnextbyte
    out (c),a
    djnz dan0_raw_loop
    jr dan0_main
    
dan0_readnextbyte:
    push bc
    ld bc,#0x0000
    ex af,af'
    call dan0_getbit
    jr nc, dan0_getbyte
    call dan0_getbit
    call dan0_rlcgetbit
    jr nc, dan0_set_buffer_ptr
    call dan0_getbit
    call dan0_rlcgetbit
    rl c
    inc c    
    inc c    
dan0_set_buffer_ptr:
    inc c
    sbc hl,bc
    dec c
    
dan0_getbyte:
    ex af,af'
    ld a,(hl)
    add hl,bc
    inc hl
    pop bc
    ret
    
dan0_rlcgetbit:
    rl c
    
dan0_getbit:
    add a,a
    ret nz
    ld a,(de)
    inc de
    rla
    ret