For less performance-sensitive interrupts (such as the vertical blank interrupt), it is possible to write the relevant handlers using only C. This is done by marking the interrupt function with special attributes:
__attribute__((assume_ss_data, interrupt))
void __far vblank_int_handler(void) {
vbl_ticks++;
// Acknowledge the hardware interrupt.
ws_hwint_ack(HWINT_VBLANK);
}
These mean the following:
__far
- This function is always a “far” call. This is required for interrupt functions - while all functions are “far” calls by default on wswan/medium
, this is not true on other subtargets.interrupt
- This function is an interrupt. This ensures it saves/restores all registers and that it uses IRET
to return from the function.assume_ss_data
- This function can assume that SS
points to the default data segment when it is called. This assumption holds true throughout the Wonderful toolchain's default libraries. However, beware that any assembler code which modifies the location of the stack segment SS
must ensure that an interrupt function with this attribute is never called during its execution.libws provides useful functions for configuring interrupt handlers:
// Set the function "vblank_int_handler" to run during vertical blank.
ws_hwint_set_handler(HWINT_IDX_VBLANK, (ws_int_handler_t) vblank_int_handler);
// Enable the vertical blank hardware interrupt.
ws_hwint_enable(HWINT_VBLANK);
// Disable the vertical blank hardware interrupt.
ws_hwint_disable(HWINT_VBLANK);
Watch out! ws_hwint_set_handler
expects a HWINT_IDX
parameter, while most other ws_hwint
operations - enable
, disable
, ack
- expect a HWINT
parameter.
I admit, this is a little confusing. ^^;