PVSnesLib  4.4.0
Documentation to code in C or ASM for the Nintendo SNES
Loading...
Searching...
No Matches
interrupt.h File Reference

snes interrupt support. More...

#include <snes/snestypes.h>

Go to the source code of this file.

Macros

#define HBL_READY   (1 << 6)
 H-Blank Period Flag (0=No, 1=HBlank)
 
#define INT_HVIRQ_H   (1 << 4)
 H/V IRQ (0=Disable, 1=At H=H + V=Any, 2=At V=V + H=0, 3=At H=H + V=V)
 
#define INT_HVIRQ_HV   (2 << 4)
 H/V IRQ (0=Disable, 1=At H=H + V=Any, 2=At V=V + H=0, 3=At H=H + V=V)
 
#define INT_HVIRQ_V   (1 << 5)
 H/V IRQ (0=Disable, 1=At H=H + V=Any, 2=At V=V + H=0, 3=At H=H + V=V)
 
#define INT_JOYPAD_ENABLE   (1)
 Joypad Enable (0=Disable, 1=Enable Automatic Reading of Joypad)
 
#define INT_VBLENABLE   (1 << 7)
 VBlank NMI Enable (0=Disable, 1=Enable) (Initially disabled on reset)
 
#define PAD_BUSY   (1)
 Auto-Joypad-Read Busy Flag (1=Busy) (see 4200h, and 4218h..421Fh)
 
#define REG_HVBJOY   (*(vuint8 *)0x4212)
 H/V-Blank flag and Joypad Busy flag (R).

 
#define REG_NMITIMEN   (*(vuint8 *)0x4200)
 Interrupt Enable and Joypad Request (W).

 
#define REG_RDNMI   (*(vuint8 *)0x4210)
 V-Blank NMI Flag and CPU Version Number (R) (Read/Ack)

 
#define REG_TIMEUP   (*(vuint8 *)0x4211)
 TIMEUP - H/V-Timer IRQ Flag (R) (Read/Ack)


 
#define VBL_READY   (1 << 7)
 V-Blank Period Flag (0=No, 1=VBlank)
 
#define WaitVBLFlag
 Wait for VBL flag to be OK

 

Functions

void nmiSet (void(*vblankRoutine)(void))
 Sets the nmi_handler (VBlank routine).
 
void WaitForVBlank (void)
 Waits for a VBlank interrupt.
 
void WaitNVBlank (u16 ntime)
 Wait for vblank interrupt ntime times

 

Variables

u16 lag_frame_counter
 Lag-frame counter.
 
void * nmi_handler
 VBlank routine.
 
u8 vblank_flag
 VBlank ISR flag.
 

Detailed Description

snes interrupt support.

VBlank ISR

PVSnesLib includes a Vertical Blank Interrupt Service Routine (VBlank ISR or NMI ISR) that will do the following actions (in this order) at the start of the Vertical Blanking Period when VBlank interrupts are enabled:

A lag-frame is when the execution time between two WaitForVBlank() calls exceeds a 50/60Hz display frame. By testing for lag-frames, the VBlank ISR will not transfer a partially populated oamMemory to the PPU OAM.

Lag-frames are determined by the vblank_flag variable, which is set on WaitForVBlank() and cleared in the VBlank ISR.

Inputs are only read on non lag-frames to prevent the input state from unexpectedly changing in the middle of the main loop (potentially causing a heisenbug). Code that loops until a button is pressed must call WaitForVBlank() within the loop otherwise it will loop forever.

The nmi_handler function pointer (set using nmiSet()) is called on every VBlank interrupt (even during force-blank / setScreenOff()). To prevent glitches, nmi_handler's should either:

  • Test vblank_flag and only update the PPU registers/memory if the vblank_flag is set.
  • Use locks or flags on every buffer/queue to prevent partially populated data from being transferred to the PPU.

Macro Definition Documentation

◆ REG_HVBJOY

#define REG_HVBJOY   (*(vuint8 *)0x4212)

H/V-Blank flag and Joypad Busy flag (R).

7 V-Blank Period Flag (0=No, 1=VBlank)
6 H-Blank Period Flag (0=No, 1=HBlank)
5-1 Not used
0 Auto-Joypad-Read Busy Flag (1=Busy) (see 4200h, and 4218h..421Fh)

The Hblank flag gets toggled in ALL scanlines (including during Vblank/Vsync).
Both Vblank and Hblank are always toggling (even during Forced Blank,
and no matter if IRQs or NMIs are enabled

◆ REG_NMITIMEN

#define REG_NMITIMEN   (*(vuint8 *)0x4200)

Interrupt Enable and Joypad Request (W).

7 VBlank NMI Enable (0=Disable, 1=Enable) (Initially disabled on reset)
6 Not used
5-4 H/V IRQ (0=Disable, 1=At H=H + V=Any, 2=At V=V + H=0, 3=At H=H + V=V)
3-1 Not used
0 Joypad Enable (0=Disable, 1=Enable Automatic Reading of Joypad)

Disabling IRQs (via bit4-5) does additionally acknowledge IRQs.
There's no such effect when disabling NMIs (via bit7).

◆ REG_RDNMI

#define REG_RDNMI   (*(vuint8 *)0x4210)

V-Blank NMI Flag and CPU Version Number (R) (Read/Ack)

7 Vblank NMI Flag (0=None, 1=Interrupt Request) (set on Begin of Vblank)
6-4 Not used
3-0 CPU 5A22 Version Number (version 2 exists)

The NMI flag gets set at begin of Vblank (this happens even if NMIs are disabled). The flag gets reset automatically
at end of Vblank, and gets also reset after reading from this register.
The SNES has only one NMI source (vblank), and the NMI flag is automatically reset (on vblank end), so there's
normally no need to read/acknowledge the flag, except one special case: If one does disable and re-enable NMIs,
then an old NMI may be executed again; acknowledging avoids that effect.
The CPU includes another internal NMI flag, which gets set when "[4200h].7 AND [4210h].7" changes from 0-to-1, and
gets cleared when the NMI gets executed (which should happen around after the next opcode) (if a DMA transfer is
in progress, then it is somewhere after the DMA, in that case the NMI can get executed outside of the Vblank
period, ie. at a time when [4210h].7 is no longer set).

◆ REG_TIMEUP

#define REG_TIMEUP   (*(vuint8 *)0x4211)

TIMEUP - H/V-Timer IRQ Flag (R) (Read/Ack)

7 H/V-Count Timer IRQ Flag (0=None, 1=Interrupt Request)
6-0 Not used

The IRQ flag is automatically reset after reading from this register
(except when reading at the very time when the IRQ condition is true
(which lasts for 4-8 master cycles), then the CPU receives bit7=1,
but register bit7 isn't cleared). The flag is also automatically cleared
when disabling IRQs (by setting 4200h.Bit5-4 to zero).
Unlike NMI handlers, IRQ handlers MUST acknowledge IRQs, otherwise the IRQ
gets executed again (ie. immediately after the RTI opcode).

Function Documentation

◆ nmiSet()

void nmiSet ( void(*)(void)  vblankRoutine)

Sets the nmi_handler (VBlank routine).

This function will also disable any active IRQ interrupts, enable VBlank interrupts and enable Joypad Auto-Read.

Parameters
vblankRoutinethe function to call on every VBlank (NMI) interrupt.

CAUTION: vblankRoutine is called on every VBlank interrupt. vblank_flag can be used to determine if vblankRoutine was called during a lag-frame.

CAUTION: This function will override the default nmi_handler. If you are using consoleDrawText(), you will need to call consoleVblank() inside vblankRoutine.

See also
VBlank-ISR, nmi_handler
Examples
graphics/Backgrounds/Mode1ContinuosScroll/Mode1ContinuosScroll.c, and graphics/Sprites/DynamicSprite/DynamicSprite.c.

◆ WaitForVBlank()

void WaitForVBlank ( void  )

Waits for a VBlank interrupt.

Sets the vblank_flag and pauses execution until the vblank_flag is cleared (by the VBlank-ISR).

CAUTION: This function will loop forever if VBlank interrupts are disabled.

Assembly note: This function will not modify the A/X/Y registers and can be called with an 8 or 16 bit .ACCU/.INDEX.

Examples
audio/effects/effects.c, audio/effectsandmusic/effectsandmusic.c, audio/music/Music.c, audio/musicGreaterThan32k/musicGreaterThan32k.c, audio/tada/Tada.c, breakpoints/src/breakpoints.c, debug/debug.c, games/breakout/breakout.c, games/likemario/LikeMario.c, graphics/Backgrounds/Mode0/Mode0.c, graphics/Backgrounds/Mode1/Mode1.c, graphics/Backgrounds/Mode1BG3HighPriority/Mode1BG3HighPriority.c, graphics/Backgrounds/Mode1ContinuosScroll/Mode1ContinuosScroll.c, graphics/Backgrounds/Mode1LZ77/Mode1LZ77.c, graphics/Backgrounds/Mode1MixedScroll/Mode1MixedScroll.c, graphics/Backgrounds/Mode1Png/Mode1.c, graphics/Backgrounds/Mode1Scroll/Mode1Scroll.c, graphics/Backgrounds/Mode3/Mode3.c, graphics/Backgrounds/Mode5/Mode5.c, graphics/Backgrounds/Mode7/Mode7.c, graphics/Backgrounds/Mode7Perspective/Mode7Perspective.c, graphics/Effects/Fading/Fading.c, graphics/Effects/GradientColors/GradientColors.c, graphics/Effects/HDMAGradient/HDMAGradient.c, graphics/Effects/MosaicShading/MosaicShading.c, graphics/Effects/ParallaxScrolling/ParallaxScrolling.c, graphics/Effects/Transparency/Transparency.c, graphics/Effects/TransparentWindow/src/main.c, graphics/Effects/Waves/Waves.c, graphics/Effects/Window/Window.c, graphics/Palette/GetColors/GetColors.c, graphics/Sprites/AnimatedSprite/AnimatedSprite.c, graphics/Sprites/DynamicEngineMetaSprite/DynamicEngineMetaSprite.c, graphics/Sprites/DynamicEngineSprite/DynamicEngineSprite.c, graphics/Sprites/DynamicSprite/DynamicSprite.c, graphics/Sprites/ObjectSize/ObjectSize.c, graphics/Sprites/SimpleSprite/SimpleSprite.c, hello_world/src/hello_world.c, input/controller/controller.c, input/mouse/mouse.c, input/multiplay5/multiplay5.c, input/superscope/superscope.c, maps/mapscroll/mapscroll.c, maps/tiled/tiled.c, memory_mapping/src/memory_mapping.c, objects/mapandobjects/mapandobjects.c, objects/moveobjects/moveobjects.c, objects/nogravityobject/nogravityobjects.c, random/random.c, scoring/scoring.c, sram/sramoffset/sramoffset.c, sram/sramsimple/sram.c, testregion/testregion.c, timer/timer.c, and typeconsole/src/pal_ntsc.c.

◆ WaitNVBlank()

void WaitNVBlank ( u16  ntime)

Wait for vblank interrupt ntime times

Parameters
ntimenumber of time to wait VBlank Interrupt
Examples
input/superscope/superscope.c.

Variable Documentation

◆ lag_frame_counter

u16 lag_frame_counter
extern

Lag-frame counter.

This variable is incremented on every VBlank Interrupt that occurs during a lag-frame.

CAUTION: The lag frame counter cannot tell the difference between a lag-frame and force-blank setup loading graphics to the PPU.

lag_frame_counter can be modified. This is useful in development builds to measure the amount of lag in a level by resetting lag_frame_counter on level load and printing lag_frame_counter on a pause screen or at the end of the level.

◆ nmi_handler

void* nmi_handler
extern

VBlank routine.

This function is called on every VBlank interrupt by the VBlank Interrupt Service Routine.

CAUTION: Writes to nmi_handler are not atomic and can cause a crash if a VBlank Interrupt occurs in the middle of the nmi_handler write. Use nmiSet() or disable NMI interrupts when modifying nmi_handler.

Assembly note: This function pointer will be called with a non-zero Direct Page register to prevent nmi_handler from clobbering the tcc imaginary registers.

See also
VBlank-ISR, nmiSet()

◆ vblank_flag

u8 vblank_flag
extern

VBlank ISR flag.

Used to detect lag-frames in the VBlank ISR.

This variable is set to a truthy (non-zero) value in WaitForVBlank() and cleared in the NMI ISR after the call to nmi_handler.

vblank_flag can be used in a custom nmi_handler to detect lag frames. Within nmi_handler:

  • If vblank_flag is truthy (non-zero), the nmi_handler was called at the end of the frame.
  • If vblank_flag is 0, the nmi_handler was called in the middle of a lag frame.

CAUTION: This variable SHOULD NOT be changed outside of WaitForVBlank()

Examples
graphics/Backgrounds/Mode1ContinuosScroll/Mode1ContinuosScroll.c, and graphics/Sprites/DynamicSprite/DynamicSprite.c.