Showing posts with label library code. Show all posts
Showing posts with label library code. Show all posts

Sunday, January 8, 2023

Clock Library Test

Clock Test

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.