OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
main.c File Reference

VBlank frame counter display, written against the gameloop framework. More...

#include <snes.h>
#include <snes/text.h>
#include <snes/gameloop.h>

Functions

int main (void)
 Entry point — hand off to gameLoopRun().
static void on_init (void)
 One-time hardware setup. Runs before the first VBlank sync.
static void on_update (void)
 Per-frame work. Called once per VBlank by the gameloop.

Detailed Description

VBlank frame counter display, written against the gameloop framework.

Displays a live frame counter that increments every VBlank (60 fps NTSC, 50 fps PAL). The simplest possible real-time display: read a hardware counter, render it as text, repeat. Doubles as the canonical demo of the opt-in gameloop framework — init() runs the standard SNES boot sequence, update() runs once per VBlank, and main() never sees a while(1) itself.

Equivalent hand-rolled main loop:

while (1) {
update();
}
void WaitForVBlank(void)
Wait for next VBlank period.

Both ship the same observable behaviour; the framework exists so the loop boilerplate isn't repeated 53 times across the SDK and so future scene/state machinery has one place to plug into.

SNES Concepts
  • VBlank frame counter (frame_count from crt0.asm, incremented by NMI)
  • Text module for real-time number display (textPrintU16; NMI auto-flushes)
  • gameloop framework — init/update callbacks, hidden VBlank sync
  • Mode 0 with 2bpp font for text output
What to Observe
  • The counter increments by 1 every frame (60 per second on NTSC)
  • At 65535 it wraps to 0 (~18 minutes of runtime)
  • The display never stutters because each frame does minimal work
Modules Used
console, sprite, dma, background, text, input, gameloop
See also
gameloop.h, console.h (getFrameCount), text.h

Function Documentation

◆ main()

int main ( void )

Entry point — hand off to gameLoopRun().

gameLoopRun never returns; the return 0 exists only to satisfy int main(void)'s control-flow contract.

◆ on_init()

void on_init ( void )
static

One-time hardware setup. Runs before the first VBlank sync.

Standard text-mode boot: textModeInit() sets BG mode + text engine, the PrintAt writes our static label into the off-screen tilemap buffer, the explicit WaitForVBlank ensures the very first NMI has fired (so the buffer has been DMA'd to VRAM) before we turn the screen on.

◆ on_update()

void on_update ( void )
static

Per-frame work. Called once per VBlank by the gameloop.

Warning
This does NOT run inside VBlank, despite following WaitForVBlank(). The handshake is the other way round: WaitForVBlank raises vblank_flag and halts, and the NMI handler clears that flag as its LAST act — after the OAM DMA, the tilemap DMA, the scroll writes and the pad read. So by the time this callback runs, VBlank is spent and the PPU is drawing again. Writing VRAM, CGRAM or OAM here is the silent failure at the top of KNOWN_LIMITATIONS.md: the write is dropped with no error.

What this callback may safely do is touch RAM — which is all the code below does. The text goes into the tilemap buffer and the NMI uploads it at the START of the next VBlank.