.export output_screen_0,clear_string,clear_vram,clear_screen_0,draw_metatile
.export set_bg_palette,set_obj_palette,play_pcm,write_pattern_0
.export write_nametable,draw_metatile
.export hex2dec8,hex2dec16

.importzp temp_lo,temp_hi,count_lo,count_hi,v2000,v2001
.importzp addr_lo,addr_hi,temp2_lo
.importzp IN0,IN1,OUT0,OUT1,OUT2,OUT3,OUT4,DIGITS

.import paltable
.import attribute_table

.include "macros.s"

.segment "CODE"


;=========================================================
                        ; draw meta-tile
                        ;
                        ; writes 4 nametable blocks and writes
                        ; the corresponding attribute table block
                        ; X = X coordinate (0 - 16)
                        ; Y = Y coordinate (0 - 15)
                        ; A = tile # start
                        ;   (example: A=$80, tiles $80,$81,$90,$91 used
                        ; temp2_lo = attribute color (0 - 3)
                        ; addr_lo,addr_hi,temp_lo,temp_hi = temp values
draw_metatile:
        pha
        sty addr_hi
        stx addr_lo

        lda #0
        sta temp_hi

        tya
        asl
        asl
        rol
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi
        sta temp_lo

        txa
        asl
        clc
        adc temp_lo
        sta temp_lo
        lda temp_hi
        adc #$20
        sta temp_hi

        lda #0
        sta $2001
        lda $2002
        lda temp_hi
        sta $2006
        lda temp_lo
        sta $2006
        
        pla
        sta $2007
        clc
        adc #1
        sta $2007

        pha

        lda temp_lo
        clc
        adc #$20
        sta temp_lo
        lda temp_hi
        adc #0
        sta $2006
        lda temp_lo
        sta $2006

        pla
        clc
        adc #$0F
        sta $2007
        clc
        adc #1
        sta $2007

        lda addr_hi
        asl
        asl
        asl
        asl
        sta addr_hi
        lda addr_lo
        clc
        adc addr_hi
        tax
        lda #$23
        sta $2006
        lda attrib_addr,x
        ldy attrib_shift,x
        sta $2006
        tax

        lda temp2_lo
 
        cpy #0
        beq @zero
        cpy #2
        beq @two 
        cpy #4
        beq @four
        cpy #6
        beq @six

@six:
        asl
        asl
        asl
        asl
        asl
        asl
        pha
        lda #%00111111
        and attribute_table,x
        pla
        ora attribute_table,x
        jmp endit
@four:
        asl
        asl
        asl
        asl
        pha
        lda #%11001111
        and attribute_table,x
        pla
        ora attribute_table,x
        jmp endit
@two:
        asl
        asl
        pha
        lda #%11110011
        and attribute_table,x
        pla
        ora attribute_table,x
        jmp endit

@zero:
        pha
        lda #%11111100
        and attribute_table,x
        pla
        ora attribute_table,x

endit:
        sta $2007



        lda v2001
        sta $2001

        rts

.segment "RODATA"

attrib_addr:
        .byte $C0,$C0,$C1,$C1,$C2,$C2,$C3,$C3
        .byte $C4,$C4,$C5,$C5,$C6,$C6,$C7,$C7
        .byte $C0,$C0,$C1,$C1,$C2,$C2,$C3,$C3
        .byte $C4,$C4,$C5,$C5,$C6,$C6,$C7,$C7
        .byte $C8,$C8,$C9,$C9,$CA,$CA,$CB,$CB
        .byte $CC,$CC,$CD,$CD,$CE,$CE,$CF,$CF
        .byte $C8,$C8,$C9,$C9,$CA,$CA,$CB,$CB
        .byte $CC,$CC,$CD,$CD,$CE,$CE,$CF,$CF
        .byte $D0,$D0,$D1,$D1,$D2,$D2,$D3,$D3
        .byte $D4,$D4,$D5,$D5,$D6,$D6,$D7,$D7
        .byte $D0,$D0,$D1,$D1,$D2,$D2,$D3,$D3
        .byte $D4,$D4,$D5,$D5,$D6,$D6,$D7,$D7
        .byte $D8,$D8,$D9,$D9,$DA,$DA,$DB,$DB
        .byte $DC,$DC,$DD,$DD,$DE,$DE,$DF,$DF
        .byte $D8,$D8,$D9,$D9,$DA,$DA,$DB,$DB
        .byte $DC,$DC,$DD,$DD,$DE,$DE,$DF,$DF
        .byte $E0,$E0,$E1,$E1,$E2,$E2,$E3,$E3
        .byte $E4,$E4,$E5,$E5,$E6,$E6,$E7,$E7
        .byte $E0,$E0,$E1,$E1,$E2,$E2,$E3,$E3
        .byte $E4,$E4,$E5,$E5,$E6,$E6,$E7,$E7
        .byte $E8,$E8,$E9,$E9,$EA,$EA,$EB,$EB
        .byte $EC,$EC,$ED,$ED,$EE,$EE,$EF,$EF
        .byte $E8,$E8,$E9,$E9,$EA,$EA,$EB,$EB
        .byte $EC,$EC,$ED,$ED,$EE,$EE,$EF,$EF
        .byte $F0,$F0,$F1,$F1,$F2,$F2,$F3,$F3
        .byte $F4,$F4,$F5,$F5,$F6,$F6,$F7,$F7
        .byte $F0,$F0,$F1,$F1,$F2,$F2,$F3,$F3
        .byte $F4,$F4,$F5,$F5,$F6,$F6,$F7,$F7
        .byte $F8,$F8,$F9,$F9,$FA,$FA,$FB,$FB
        .byte $FC,$FC,$FD,$FD,$FE,$FE,$FF,$FF
        .byte $F8,$F8,$F9,$F9,$FA,$FA,$FB,$FB
        .byte $FC,$FC,$FD,$FD,$FE,$FE,$FF,$FF

attrib_shift:
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6
        .byte 0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2
        .byte 4,6,4,6,4,6,4,6,4,6,4,6,4,6,4,6


.code




;---------------------------------------------------------
;=========================================================
                        ; Write nametable #0
                        ;
                        ; addr_lo = pointer to nametable data

write_nametable:
        lda #0
        sta $2000
        sta $2001
        tay

        lda $2002
        lda #$20
        sta $2006
        sty $2006

        ldx #4
:
        lda (addr_lo),y
        sta $2007
        iny
        bne :-
        inc addr_hi
        dex
        bne :-

        rts


;---------------------------------------------------------


;=========================================================
;                       ; Print a string of text (or other data)
;                       ; to nametable #0 ($2000-$2FFF)
;                       ;
;                       ; addr_lo,addr_hi = address to null-terminated string
;                       ; X = X starting coordinate (0 - 31)
;                       ; Y = Y starting coordinate (0 - 29)
;                       ; Y coordinates 30 and 31 are "rows" of attribute memory
;---------------------------------------------------------
output_screen_0:
        
        lda v2000
        and #%00000100          ; preserve H/V write setting
        sta $2000
        lda #0
        sta $2001
        sta temp_hi
        lda $2002
        
        tya

        asl                     ; calculate VRAM address
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi

        stx temp_lo
        clc
        adc temp_lo
        sta temp_lo
        lda temp_hi
        adc #$20
        sta $2006
        lda temp_lo
        sta $2006

        ldy #0
:
        lda (addr_lo),y
        beq :+
        sta $2007

        iny
        bne :-
        inc addr_hi
        jmp :-
:

        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts


;---------------------------------------------------------

;=========================================================
;                       ; Clear string (write zeros)
;                       ; 
;                       ; A = number of bytes to clear
;                       ; X = X starting coordinate (0 - 31)
;                       ; Y = Y starting coordinate (0 - 29)
;                       ; Y coordinates 30 and 31 are "rows" of attribute memory
;                       ;
;                       ; destroys: A, X, Y
;                       ; upon exit: X, Y = 0
;---------------------------------------------------------

clear_string:
        pha
        lda v2000
        and #%00000100
        sta $2000
        lda #0
        sta $2001
        sta temp_hi
        lda $2002
        
        tya

        asl
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi
        rol
        rol temp_hi

        stx temp_lo
        clc
        adc temp_lo
        sta temp_lo
        lda temp_hi
        adc #$20
        sta $2006
        lda temp_lo
        sta $2006

        pla
        tax
        lda #0
:
        sta $2007
        dex
        bne :-

        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts


;---------------------------------------------------------


;=========================================================
;                       ; Clear Vram
;                       ; ($0000 - $3FFF)
;                       ; destroys: A, X, Y
;                       ; upon exit: X, Y = 0
;---------------------------------------------------------
clear_vram:
        lda #0
        sta $2000
        sta $2001

        lda $2002
        lda #0
        tay             
        ldx #$40
        sta $2006
        sta $2006
:
        sta $2007
        iny
        bne :-
        dex
        bne :-

        stx $2006
        stx $2006

        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts

;---------------------------------------------------------

;=========================================================
;                       ; Clear Nametable 0
;                       ; ($2000 - $2FFF)
;                       ; destroys: A, X, Y
;                       ; upon exit: X, Y = 0
;---------------------------------------------------------
clear_screen_0:
        lda #0
        sta $2000
        sta $2001

        lda $2002
        lda #$20
        sta $2006
        lda #0
        sta $2006
        tax
        ldy #$0F
:
        sta $2007
        dex
        bne :-
        dey
        bne :-

        stx $2006
        stx $2006

        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts


;=========================================================
;                       ; Write backgroud palette (ROM)
;                       ; A = palette # (0 - $7F)
;                       ; paltable = palette address table
;                       ; destroys A, Y, addr_lo, addr_hi
;---------------------------------------------------------
set_bg_palette:
        ldy #0
        sty $2000
        sty $2001

        asl
        tay
        lda paltable,y
        sta addr_lo
        lda paltable+1,y
        sta addr_hi

        lda $2002
        lda #$3F        ; write palette
        sta $2006
        lda #0
        sta $2006

        tay
:
        lda (addr_lo),y
        sta $2007
        iny
        cpy #$10
        bne :-

        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts

;---------------------------------------------------------

;=========================================================
;                       ; Write sprite palette (ROM)
;                       ; A = palette # (0 - $7F)
;                       ; paltable = palette address table
;                       ; destroys A, Y, addr_lo, addr_hi
;---------------------------------------------------------
set_obj_palette:
        ldy #0
        sty $2000
        sty $2001

        asl
        tay
        lda paltable,y
        sta addr_lo
        lda paltable+1,y
        sta addr_hi

        lda #$3F        ; write palette
        sta $2006
        lda #$10
        sta $2006

        ldy #0
:
        lda (addr_lo),y
        sta $2007
        iny
        cpy #$10
        bne :-

        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts

;---------------------------------------------------------
;---------------------------------------------------------
;               Raw PCM player
;               this takes control until the sample is finished playing
;               format: 8-bit unsigned RAW 11050hz
;               addr_lo,addr_hi = sample location
;               count_lo,count_hi = sample length
;---------------------------------------------------------
play_pcm:
        ldy #0
rawloop:
        lda (addr_lo),y
        lsr
        sta $4011

        inc16 addr_lo
        cmp16 addr_lo,count_lo,continue_raw

        rts

continue_raw:
        ldy #10
:
        dey
        bne :-
        nop

        jmp rawloop


;---------------------------------------------------------
;---------------------------------------------------------
;               Load CHR-RAM Pattern Table #0
;
;               addr_lo,addr_hi = address to pattern data
;               A = tile number to start on
;               X = number of tiles to write
;
;               destroys: A, X, Y, temp_hi,addr_lo,addr_hi
;---------------------------------------------------------
write_pattern_0:        

        ldy #0
        sty temp_hi
        asl a
        rol temp_hi
        rol a
        rol temp_hi
        rol a
        rol temp_hi
        rol a
        rol temp_hi
        pha

        lda addr_lo
        sec
        sbc #$F0                ; compensate for "fast" tile loading trick
        sta addr_lo
        lda addr_hi
        sbc #0
        sta addr_hi

        sty $2000
        sty $2001

        lda $2002
        lda temp_hi
        sta $2006
        pla
        sta $2006

        ldy #$F0
:
        lda (addr_lo),y
        sta $2007
        iny
        bne :-

        ldy #$F0

        lda addr_lo
        clc
        adc #16
        sta addr_lo
        lda addr_hi
        adc #0
        sta addr_hi

        dex
        bne :-   


        lda v2001
        sta $2001
        lda v2000
        sta $2000

        rts


;---------------------------------------------------------

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                    ;
; HEX2DEC8 / HEX2DEC16                               ;
;                                                    ;
; Converts hex numbers to decimal and counts digits. ;
;                                                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                    ;
; HEX2DEC8 (converts 8-bit hex to 3-digit decimal)   ;
;                                                    ;
; In: A (number to be converted)                     ;
;                                                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                    ;
; HEX2DEC16 (converts 16-bit hex to 5-digit decimal) ;
;                                                    ;
; In: A (low byte of number to be converted)         ;
;     X (high byte ")                                ;
;                                                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                    ;
; Out: OUT.0 - OUT.4 (the converted number)          ;
;      DIGITS (digit count; 1 = 1-digit, etc)        ;
;                                                    ;
; Modifies: A, X, IN.0, IN.1, OUT.0 - OUT.4          ;
;                                                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

hex2dec_d4: .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3
hex2dec_d3: .byte 0,0,0,0,0,0,0,0,0,0,1,2,4,8,6,2
hex2dec_d2: .byte 0,0,0,0,0,0,0,1,2,5,0,0,0,1,3,7
hex2dec_d1: .byte 0,0,0,0,1,3,6,2,5,1,2,4,9,9,8,6
hex2dec_d0: .byte 1,2,4,8,6,2,4,8,6,2,4,8,6,2,4,8


hex2dec8:
        ldx #0
hex2dec16:
        sta IN0
        stx IN1
        ldx #0
        stx OUT0
        stx OUT1
        stx OUT2
        stx OUT3
        stx OUT4
do_hex2dec:
        lsr IN1
        ror IN0
        bcc hex2dec_no_add
        lda OUT0
        adc hex2dec_d0,x
        cmp #10
        bcs no_d0_carry
        sec
        sbc #10
        inc OUT1
no_d0_carry:
        sta OUT0
        lda OUT1
        adc hex2dec_d1,x
        cmp #10
        bcs no_d1_carry
        sec
        sbc #10
        inc OUT2
no_d1_carry:
        sta OUT1
        lda OUT2
        adc hex2dec_d2,x
        cmp #10
        bcs no_d2_carry
        sec
        sbc #10
        inc OUT3
no_d2_carry:
        sta OUT2
        lda OUT3
        adc hex2dec_d3,x
        cmp #10
        bcs no_d3_carry
        sec
        sbc #10
        inc OUT3
no_d3_carry:
        sta OUT3
        lda OUT4
        adc hex2dec_d4,x
        sta OUT4
hex2dec_no_add:
        inx
        cpx #5
        bne do_hex2dec
digit_count:
        dex
        cpx #$FF
        bne digit_count_continue
        ldx #1
        jmp digit_count_finished
digit_count_continue:
        lda OUT0,x
        beq digit_count
digit_count_finished:
        stx DIGITS


        rts