Test program for my clock library. The library code runs a real time clock that adjusts for the NES's ~60.1 frames/second framerate. A clock can be updated once per frame to count about 1/60th of a second, but for a more accurate clock, consider the following:
60.098811862348404716732985230828 frames/sec = 0.01663926405550947066275456212502 seconds/frame = 1.663926405550947066275456212502 hundredths seconds/frame fractional part = 0.663926405550947066275456212502 fractional part of 65536 ($10000) = 0.663926405550947066275456212502 * 65536 = 43,511.080914186866935428298342531 drop the decimal part: = 43,511
The clock routine is as follows:
FRACTIONAL_CONSTANT = 43511
; --------------------------------------------------------------------------------------------
; execute every NMI for a real time clock counter
func clockTick
mb fractional[ 0 ] = fractional[ 0 ] + #<FRACTIONAL_CONSTANT
mb fractional[ 1 ] = fractional[ 1 ] +c #>FRACTIONAL_CONSTANT
; add 1 to hundredths every frame plus any carry:
mb hundredths = hundredths +c #1
; a still holds hundredths
if ( a >= #100 )
mb hundredths = a -c #100 ; carry will be set
inc seconds
if ( lda seconds = #60 )
ldx #0
stx seconds
inc minutes
if ( lda minutes = #60 )
stx minutes
inc hours
endif
endif
endif
rts
endfunc
The main routine:
; --------------------------------------------------------------------------------------------
; File: mainGameLoopState
; --------------------------------------------------------------------------------------------
; this State is one level above rootState
; --------------------------------------------------------------------------------------------
; required headers:
.include "config.h"
.include "header/memory.h"
.include "header/funcCall.h"
.include "header/ca65hl.h"
; --------------------------------------------------------------------------------------------
; Define State:
identifyState "mainGameLoopState"
loadState "mainGameLoopState"
; --------------------------------------------------------------------------------------------
; Constants for State:
; --------------------------------------------------------------------------------------------
; Headers for State:
; standard library
.include "header/string.h"
.include "header/nmi.h"
.include "header/controller.h"
.include "header/condes.h"
.include "header/nes_constants.h"
.include "header/ppu.h"
.include "header/clock.h"
; --------------------------------------------------------------------------------------------
; Code segment for State:
.segment "CODE"
; --------------------------------------------------------------------------------------------
; global memory settings:
resBSS clockRunning .byte
; --------------------------------------------------------------------------------------------
; Imports:
; --------------------------------------------------------------------------------------------
; Exports:
declarefunc nmiEnd
; --------------------------------------------------------------------------------------------
; States:
declarefunc mainGameLoopState
; --------------------------------------------------------------------------------------------
; Forward Declarations:
.pushseg
.segment "RODATA"
palette:
.byte $01,$36,$05,$16,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
cursorPos:
.byte 0, 3, 6, 9
.popseg
func mainGameLoopState
resBSS timeStr .byte 4 ; 3 byte string plus terminator
resBSS cursor .byte ; position as 0 to 3
resBSS i .byte ; loop counter
mb cursor = #0
mb clockRunning = #1
call nmi::waitForNMI ; wait for vblank to write palette
call ppu::setBackgroundPalette, { &palette }
jPrintRenderMode off
jPrintSetMaxCol 32
jPrintSetCursor 9, 6
jPrint "Clock Test!"
jPrint
jPrint
jPrint
jPrint "00:00:00:00"
jPrintSetCursor 1, 14
jPrint "Press START to Pause"
jPrint "Press UP/DOWN to change value"
jPrint "Press A to reset value"
jPrintEnd
PPU_RENDER_ON
repeat
; draw the time:
; i = 0 -> hours
; i = 1 -> minutes
; i = 2 -> seconds
; i = 3 -> hundredths
for ( mb i := #3, !N, dec i ) ; i: 3 to 0
ldx i
call str::byteToDecimal, { clock::time[ x ], &timeStr }
ldx i : mb a = cursorPos[ x ] + #9
call str::print, { a , #10, &(timeStr + 1) } ; only print the last 2 digits
next
; draw cursor
jPrintRenderMode on
jPrintSetCursor 10, 11
jPrint " " ; create a blank buffer
jPrintEnd
ldy cursor
txa ; x holds vramBufferIndex
mb x = a + cursorPos[ y ]
mb ppu::vramBuffer[ x ] = #$1F ; arrow symbol
; process input:
lda controller::pressedNew : tay ; store a copy of buttons in y to quickly restore a
ldx cursor
if ( !zero && a & #BUTTON_LEFT )
dex
elseif ( tya : a & #BUTTON_RIGHT && x < #3 )
inx
elseif ( tya : a & #BUTTON_START ), !Z
inc clockRunning
elseif ( tya : a & #BUTTON_A )
mb clock::time[ x ] = #0
elseif ( tya : a & #BUTTON_UP && clock::time[ x ] <> #59 ), Z
inc clock::time[ x ]
elseif ( tya : a & #BUTTON_DOWN && clock::time[ x ] ), !Z
dec clock::time[ x ]
endif
stx cursor
call nmi::waitForNMI
forever
endfunc
; --------------------------------------------------------------------------------------------
func nmiEnd
call controller::readPort, { #0 }
call controller::autoRepeatButtons, { #0, #$FF } ; allow all to auto repeat
if ( clockRunning & #1 )
call clock::clockTick
endif
rts
endfunc
; --------------------------------------------------------------------------------------------
Get the ROM here.
No comments:
Post a Comment