snake6502/src/subroutines.asm

136 lines
3.8 KiB
NASM

; Subroutines
; ----------------------------------------------------------------------
; Do some math to calculate tile address in video memory
; using x,y coordinates
; Formula: addr = $400 + y * SCREEN_W + x
calcTileMem:
; Save registers
pha
txa
pha
tya
pha
; Set tileMem to $400
lda #$00
sta tileMem
lda #$04
sta tileMem + 1
ldy calcTileY ; Get head Y coordinate
calcTileMult:
tya
beq calcTileEnd ; if Y is equal to zero, nothing to do, just skip moltiplication, else...
dey ; decrement Y
clc
lda #SCREEN_W ; A = screen width = 40
adc tileMem ; A = screen width + tileMem (low)
sta tileMem ; update tileMem (low)
lda #0 ; do the same with higher byte: A = 0
adc tileMem + 1 ; add (eventual) carry
sta tileMem + 1 ; update tileMem (high)
jmp calcTileMult ; do again until Y == 0
calcTileEnd: ; now multiplication is ended, so add X
lda calcTileX
adc tileMem
sta tileMem
lda #0
adc tileMem + 1
sta tileMem + 1
; Restore old registers
pla
tay
pla
tax
pla
rts
; Print a byte in hexadecimal
; A input register for byte to print
; Y input register for printing colum (on first line)
printByte:
; Copy parameter also in X
tax
lsr ; Take most significant nibble
lsr
lsr
lsr
jsr printDigit
sta $400,y ; print msb char
txa ; Take least significant nibble (use previous copy)
and #$0f
jsr printDigit
sta $401,y ; print lsb char
rts
; Transform a base-36 digit into a Commodore screen code
; Leave input digit in accumulator; returns output screen code in accumulator
printDigit:
cmp #10
bcs printDigitL ; if it is not a decimal digit, then go to printDigitL
clc ; it is a decimal digit! Just add `0` (48)
adc #48
ora #$80 ; reverse color
rts
printDigitL: ; it is not a decimal digit, then...
sec
sbc #10 ; take away 10
clc
adc #1 ; add 1, so you obtain something in [A-F]
ora #$80 ; reverse color
rts
; Print null-terminated string on status bar
; address of string is given in input using memory location printStatusString
printStatus:
ldy #0
printStatusLoop:
lda (printStatusString),y
beq printStatusEnd
cmp #$20
bne printStatusSkipSpace
lda #$60
printStatusSkipSpace:
sec
sbc #$40 ; convert from standard ASCII to Commodore screen code
ora #$80 ; reverse color
sta $413,y
iny
jmp printStatusLoop
printStatusEnd:
rts
; Print string for intro
; Input parameters:
; printIntroString pointer to string to be printed (source)
; introScreenStart pointer to text video memory on screen where to print (dest)
printIntro:
ldy #0
printIntroLoop:
lda (printIntroString),y ; get char from string
beq printIntroEnd ; if zero, then end (string must be null-terminated)
cmp #$40 ; is char greater or equal to #$40 = #64 = `@' ?
bcc printIntroEndCheck ; if not, it is less, thus it must be
; a full stop, comma, colon or something
; that actually has the same value in both
; true ASCII and in PET screen codes
; otherwise, it is greater than `@`, so must
; subtract 64 because CBM and its encodings
; are simply a big shit
sec
sbc #$40
printIntroEndCheck:
sta (introScreenStart),y ; put screen code to screen
iny ; next char in string
jmp printIntroLoop
printIntroEnd:
rts