.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