The <intr.h> Header File

Routines for creating interrupt handlers

Language Extensions

DEFINE_INT_HANDLER
Defines an interrupt handler function.

Functions

AUTO_INT
Gets an address of an interrupt vector.
DisablePRG
Disables the programmable rate generator.
DUMMY_HANDLER
A dummy interrupt handler doing nothing.
EnablePRG
Enables the programmable rate generator.
ExecuteHandler
Executes an interrupt handler.
GetIntVec
Gets an interrupt vector.
IsPRGEnabled
Determines whether the programmable rate generator is enabled.
PRG_getRate
Returns the speed at which the programmable rate generator is incremented.
PRG_getStart
Returns the starting value of the programmable rate generator variable.
PRG_getValue
Returns the current value stored in the programmable rate generator.
PRG_setRate
Sets the speed at which the programmable rate generator is incremented.
PRG_setStart
Specifies the starting value of the variable incremented by the programmable rate generator.
SetIntVec
Sets an interrupt vector.
TRAP
Gets an address of a trap vector.

Constants

AUTO_INT_COUNT
Returns the total number of Auto-Int vectors.
FIRST_AUTO_INT
Returns the index of the first Auto-Int vector.
FIRST_TRAP
Returns the index of the first Auto-Int vector.
LAST_AUTO_INT
Returns the index of the last Auto-Int vector.
LAST_TRAP
Returns the index of the last Auto-Int vector.
TRAP_COUNT
Returns the total number of Auto-Int vectors.

Predefined Types

Bool
An enumeration to describe true or false values.
INT_HANDLER
A pointer to an interrupt handler.
IntVecs
An enumeration describing interrupt vectors.

DEFINE_INT_HANDLER

Defines an interrupt handler function.

DEFINE_INT_HANDLER is a language extension macro which is used for defining interrupt handlers. The syntax is similar to function definition:

DEFINE_INT_HANDLER (HandlerName)
{
  // The body of the handler...
}

Note, however, that DEFINE_INT_HANDLER does not define a standard function: it constructs an object named HandlerName of INT_HANDLER type, which is initialized to point to the handler body (implemented internally as a function, but unaccessable directly to the rest of the program). So, you can not call the interrupt handler using a standard call construction like

HandlerName ();

Such behaviour is implemented due to safety reasons: interrupt handlers are not supposed to be executed directly. If you need to call the interrupt handler anyway, you can use ExecuteHandler function. Here is an example of the program which installs the new (user-defined) interrupt handler for auto interrupt 5 (the programable timer interrupt), in which the old (default) handler is called as well (called "Interrupt Handler"):

// Interrupt handler incrementing a counter

#define USE_TI89              // Compile for TI-89
#define USE_TI92PLUS          // Compile for TI-92 Plus
#define USE_V200              // Compile for V200

#define OPTIMIZE_ROM_CALLS    // Use ROM Call Optimization
#define MIN_AMS 100           // Compile for AMS 1.00 or higher
#define SAVE_SCREEN           // Save/Restore LCD Contents

#include <tigcclib.h>         // Include All Header Files

INT_HANDLER OldInt5 = NULL;
volatile int Counter = 0;

DEFINE_INT_HANDLER(MyInt5)
{
  Counter++;
  ExecuteHandler (OldInt5);
}

void _main(void)
{
  OldInt5 = GetIntVec (AUTO_INT_5);
  SetIntVec (AUTO_INT_5, MyInt5);
  while (!kbhit()) printf_xy (50, 50, "Counter = %d  ", Counter);
  SetIntVec (AUTO_INT_5, OldInt5);
  GKeyFlush ();
}

The only legal usage of INT_HANDLER objects is to be passed as arguments to the functions SetIntVec or ExecuteHandler.

Be aware that the variable Counter in above example is declared as volatile. In fact, any global variable which may be changed by the interrupt handler should be declared as volatile, especially if it is accessed from the other parts of the program (i.e. out of the interrupt handler). This is necessary to prevent various optimizations which may be fooled by the fact that the variable may be changed in a way which is completely unpredictable from the aspect of the normal program flow. For example, various optimizations may force keeping the variable content in a register, so if the variable is changed asynchronously, the compiler will not know anything about it. volatile will prevent keeping the variable in a register, so it will be reloaded from the memory on each access. The example given above will still work if you omit the volatile keyword, but more complicated programs will probably not work correctly without it.


AUTO_INT

#define AUTO_INT(IntNo) ((long) (IntNo) * 4 + 0x60)

Gets an address of an interrupt vector.

AUTO_INT returns the absolute address where the interrupt vector for Auto-Int IntNo is located.

You can use it together with FIRST_AUTO_INT, LAST_AUTO_INT, and AUTO_INT_COUNT to loop through all interrupts.


DisablePRG

void DisablePRG (void);

Disables the programmable rate generator.

DisablePRG disables the programmable rate generator, which means that the value determined by PRG_getValue does not change and AUTO_INT_5 is not called any more.

Note: Auto interrupt 5 is used by the AMS, so the previous state (which can be determined using IsPRGEnabled) should be restored before the program terminates.

This macro does not work in VTI 2.5 Beta 5.

See also: EnablePRG, OSRegisterTimer


DUMMY_HANDLER

INT_HANDLER DUMMY_HANDLER;

A dummy interrupt handler doing nothing.

DUMMY_HANDLER is an interrupt handler of type INT_HANDLER which consists only of 'rte'. The purpose of this handler is to redirect an interrupt vector to "nothing", in cases when disabling interrupts is not possible. For example, you can not disable auto-int 1 in grayscale programs, because grayscale support is based on it. Grayscale support installs its own auto-int 1 handler, which executes the previously installed handler at the end. Suppose that you don't want it to call the default auto-int 1 handler, which trashes the status line by displaying keyboard status indicators. You can redirect auto-int 1 to the dummy handler before enabling grayscale, so after the grayscale interrupt, the dummy handler (i.e. nothing) will be called instead of the default auto-int 1 handler:

INT_HANDLER save_int_1;
...
save_int_1 = GetIntVec (AUTO_INT_1);
SetIntVec (AUTO_INT_1, DUMMY_HANDLER);   // redirect auto-int 1 to "nothing"
// enable grayscale
// do whatever you want in grayscale
// disable grayscale
SetIntVec (AUTO_INT_1, save_int_1);

EnablePRG

void EnablePRG (void);

Enables the programmable rate generator.

The programmable rate generator is used by the AMS and is normally on. If it has been disabled using DisablePRG, EnablePRG re-enables it.

This macro does not work in VTI 2.5 Beta 5.

See also: DisablePRG, OSRegisterTimer


ExecuteHandler

void ExecuteHandler (INT_HANDLER Handler);

Executes an interrupt handler.

ExecuteHandler executes the interrupt handler pointed to by Handler. The only purpose of this function is to allow calling the previous interrupt handler (usually the default one) from the user-defined interrupt handler. This function must not be executed from anywhere out of the user-defined interrupt handler (defined using DEFINE_INT_HANDLER). Otherwise, you will get the "Privilege Violation" crash, because all interrupt handlers expect to be executed in the supervisor CPU mode. Parameter Handler should be either the value returned from GetIntVec, or the address of a user-defined interrupt handler defined using DEFINE_INT_HANDLER. It must not be the address of an ordinary C function. See DEFINE_INT_HANDLER for an example of usage.


GetIntVec

INT_HANDLER GetIntVec (long IntVec);

Gets an interrupt vector.

GetIntVec gets the content of the interrupt vector located at the absolute address IntVec (typical values of IntVec are defined in enum IntVecs). Typical usage of this function is to get the current content of the interrupt vector to be restored later. See DEFINE_INT_HANDLER for an example of usage.

See also: SetIntVec, IntVecs


IsPRGEnabled

short IsPRGEnabled (void);

Determines whether the programmable rate generator is enabled.

The programmable rate generator is used by the AMS and is normally on. However, if you enable or disable it in a program, first you should check whether it is currently enabled, which can be done with this macro.

See also: EnablePRG, DisablePRG


PRG_getRate

short PRG_getRate (void);

Returns the speed at which the programmable rate generator is incremented.

This function returns the current speed of the programmable rate generator. For more information, see PRG_setRate.

See also: PRG_setRate


PRG_getStart

unsigned char PRG_getStart (void);

Returns the starting value of the programmable rate generator variable.

PRG_getStart returns the starting value of the variable incremented by the programmable rate generator. For more information about this variable, see PRG_getValue.

See also: PRG_setStart, PRG_getValue


PRG_getValue

unsigned char PRG_getValue (void);

Returns the current value stored in the programmable rate generator.

PRG_getValue returns the current value of the variable incremented by the programmable rate generator. When this value overflows from 0xFF to 0x00, auto interrupt 5 will be triggered (see PRG_setStart for more information about this value, and SetIntVec for more information about auto interrupts).

See also: PRG_setStart, PRG_setRate


PRG_setRate

void PRG_setRate (short rate);

Sets the speed at which the programmable rate generator is incremented.

The programmable rate generator's speed can be controlled by this function. Valid values for rate are as follows:

Value Speed
0 OSC2/2^5 (highest rate)
1 OSC2/2^9 (default)
2 OSC2/2^12
3 OSC2/2^18 (lowest rate)

Note: Before exiting your program, it is good practice to restore the programmable rate generator to its previous value (determined by PRG_getRate) so that the AMS does not misbehave.

See also: PRG_getRate


PRG_setStart

void PRG_setStart (unsigned char val);

Specifies the starting value of the variable incremented by the programmable rate generator.

PRG_setStart sets the starting value of the variable incremented by the programmable rate generator. This variable is incremented by 1 every time the programmable rate generator is triggered (at a speed which can be set using PRG_setRate). When it overflows from 0xFF to 0x00, auto interrupt 5 is triggered, and it is reset to val. To conclude, the way the value of this variable changes is shown here:

..., val, val+1, ..., 0xFF, 0x00, (auto interrupt 5), val, val+1, ...

Note: If a program uses this function, it should restore the previous value before the end of the program, as determined by PRG_getStart.

See also: PRG_getStart, PRG_setRate


SetIntVec

void SetIntVec (long IntVec, INT_HANDLER Handler);

Sets an interrupt vector.

SetIntVec sets the interrupt vector located at the absolute address IntVec to the interrupt handler pointed to by Handler. Handler should be either a value returned from GetIntVec, or the address of a user-defined interrupt handler defined using DEFINE_INT_HANDLER. Note that Handler may not be the address of an ordinary C function.

Typical values of IntVec are given in the following table as enumerated in the IntVecs enum:

AddressAssociated ConstantTriggered On
0x04INT_VEC_RESETReset (contains pointer to OS entry point)
0x08INT_VEC_BUS_ERRORBus error
0x0CINT_VEC_ADDRESS_ERRORAddress error (accessing a short or long at an odd address)
0x10INT_VEC_ILLEGAL_INSTRUCTIONIllegal instruction
0x14INT_VEC_ZERO_DIVIDEDivision by zero
0x18INT_VEC_CHK_INSCHK instruction
0x1CINT_VEC_TRAPV_INSTRAPV instruction
0x20INT_VEC_PRIVILEGE_VIOLATIONPrivilege violation
0x24INT_VEC_TRACECode Tracing
0x28INT_VEC_LINE_1010Special instructions generated by ER_throw (0xA???)
0x2CINT_VEC_LINE_1111F-Line instructions (0xF???)
0x3CINT_VEC_UNINITIALIZED_INTUninitialized interrupt vector
0x60INT_VEC_SPURIOUS_INTSpurious interrupt
0x64AUTO_INT_1Main timer hardware interrupt running at approximately 350 Hz
0x68AUTO_INT_2
INT_VEC_KEY_PRESS
Key press (triggered periodically while key(s) other than 'ON' are held down; the rate depends both on battery strength and on which keys are being held down, and is usually in the ballpark of about 600 Hz)
0x6CAUTO_INT_3On most calculators, triggers once per second if enabled using a certain instruction
0x70AUTO_INT_4
INT_VEC_LINK
Link port activity
0x74AUTO_INT_5System timer running at approximately 18 Hz (see PRG_setRate, PRG_setStart)
0x78AUTO_INT_6
INT_VEC_ON_KEY_PRESS
'ON' key press
0x7CAUTO_INT_7
INT_VEC_STACK_OVERFLOW
Stack overflow (actually results in Protected Memory Violation)

All traps may be triggered manually using the TRAP assembler instruction.

AddressAssociated ConstantDefault Behavior
0x80TRAP_0(unknown)
0x84TRAP_1
INT_VEC_INT_MASK
Change interrupt mask (bits 8-10 of %sr) to %d0.w, output old mask in %d0.l
0x88TRAP_2
INT_VEC_MANUAL_RESET
Reset calculator
0x8CTRAP_3(unknown)
0x90TRAP_4
INT_VEC_OFF
Turn the calculator off and wait for 'ON' key press
0x94TRAP_5(unknown)
0x98TRAP_6(unknown)
0x9CTRAP_7(unknown)
0xA0TRAP_8(unknown)
0xA4TRAP_9Access to various system routines
0xA8TRAP_10
INT_VEC_SELF_TEST
Enter self test
0xACTRAP_11
INT_VEC_ARCHIVE
Print "Trap 11" and freeze
0xB0TRAP_12Put the processor in supervisor mode; return the previous value of the status register in %d0:w
0xB4TRAP_13Print "Trap 13" and freeze
0xB8TRAP_14Print "Trap 14" and freeze
0xBCTRAP_15
INT_VEC_ER_THROW
Print "ER_throw" and freeze

See DEFINE_INT_HANDLER for an example of usage.

See also: GetIntVec, IntVecs, DEFINE_INT_HANDLER


TRAP

#define TRAP(TrapNo) ((long) (TrapNo) * 4 + 0x80)

Gets an address of a trap vector.

TRAP returns the absolute address where the interrupt vector for Trap TrapNo is located.

You can use it together with FIRST_TRAP, LAST_TRAP, and TRAP_COUNT to loop through all traps.


AUTO_INT_COUNT

#define AUTO_INT_COUNT (LAST_AUTO_INT - FIRST_AUTO_INT + 1)

Returns the total number of Auto-Int vectors.

You can use it together with FIRST_AUTO_INT, LAST_AUTO_INT, and AUTO_INT to loop through all interrupts.


FIRST_AUTO_INT

#define FIRST_AUTO_INT 1

Returns the index of the first Auto-Int vector.

You can use it together with LAST_AUTO_INT, AUTO_INT_COUNT, and AUTO_INT to loop through all interrupts.


FIRST_TRAP

#define FIRST_TRAP 0

Returns the index of the first Auto-Int vector.

You can use it together with LAST_TRAP, TRAP_COUNT, and TRAP to loop through all interrupts.


LAST_AUTO_INT

#define LAST_AUTO_INT 7

Returns the index of the last Auto-Int vector.

You can use this together with FIRST_AUTO_INT, AUTO_INT_COUNT, and AUTO_INT to loop through all interrupts.


LAST_TRAP

#define LAST_TRAP 15

Returns the index of the last Auto-Int vector.

You can use this together with FIRST_TRAP, TRAP_COUNT, and TRAP to loop through all interrupts.


TRAP_COUNT

#define TRAP_COUNT (LAST_TRAP - FIRST_TRAP + 1)

Returns the total number of Auto-Int vectors.

You can use it together with FIRST_TRAP, LAST_TRAP, and TRAP to loop through all interrupts.


INT_HANDLER

A pointer to an interrupt handler.

INT_HANDLER is a pointer type which represents the address of the interrupt handler. It might be logical that INT_HANDLER is defined as a pointer to a void function, i.e.

typedef void (*INT_HANDLER)(void);

But this is not true. Instead, INT_HANDLER is a pointer to a strange structure (its shape is completely irrelevant, as this structure is never used, neither explicitely nor implicitely). Such unusual behaviour is implemented due to safety reasons. First, with such implementation it is impossible to call an interrupt handler using a simple function call (which would be possible if INT_HANDLER is implemented as a pointer to a function). Second, as INT_HANDLER is a pointer to an unusual structure, the compiler can emit a warning if you try to pass anything which is not created using DEFINE_INT_HANDLER or returned from GetIntVec to the functions SetIntVec and ExecuteHandler. For example, you will be warned if you try to pass an ordinary void function instead of properly-defined interrupt handler to the SetIntVec.


IntVecs

enum IntVecs {AUTO_INT_1 = 0x64, AUTO_INT_2 = 0x68, AUTO_INT_3 = 0x6C, AUTO_INT_4 = 0x70, AUTO_INT_5 = 0x74, AUTO_INT_6 = 0x78, AUTO_INT_7 = 0x7C, TRAP_0 = 0x80, TRAP_1 = 0x84, TRAP_2 = 0x88, TRAP_3 = 0x8C, TRAP_4 = 0x90, TRAP_5 = 0x94, TRAP_6 = 0x98, TRAP_7 = 0x9C, TRAP_8 = 0xA0, TRAP_9 = 0xA4, TRAP_10 = 0xA8, TRAP_11 = 0xAC, TRAP_12 = 0xB0, TRAP_13 = 0xB4, TRAP_14 = 0xB8, TRAP_15 = 0xBC, INT_VEC_RESET = 0x04, INT_VEC_BUS_ERROR = 0x08, INT_VEC_ADDRESS_ERROR = 0x0C, INT_VEC_ILLEGAL_INSTRUCTION = 0x10, INT_VEC_ZERO_DIVIDE = 0x14, INT_VEC_CHK_INS = 0x18, INT_VEC_TRAPV_INS = 0x1C, INT_VEC_PRIVILEGE_VIOLATION = 0x20, INT_VEC_TRACE = 0x24, INT_VEC_LINE_1010 = 0x28, INT_VEC_LINE_1111 = 0x2C, INT_VEC_UNINITIALIZED_INT = 0x3C, INT_VEC_SPURIOUS_INT = 0x60, INT_VEC_KEY_PRESS = 0x68, INT_VEC_LINK = 0x70, INT_VEC_ON_KEY_PRESS = 0x78, INT_VEC_STACK_OVERFLOW = 0x7C, INT_VEC_INT_MASK = 0x84, INT_VEC_MANUAL_RESET = 0x88, INT_VEC_OFF = 0x90, INT_VEC_SELF_TEST = 0xA8, INT_VEC_ARCHIVE = 0xAC, INT_VEC_ER_THROW = 0xBC};

An enumeration describing interrupt vectors.

IntVecs is an enumeration for easier access to the standard interrupt vectors. These include the usual auto-interrupts and traps as well as the other predefined interrupts, which are triggered in special cases.

Note that some traps have their own names. For example, TRAP_4 equals INT_VEC_OFF.

Deprecated alias: AutoInts

See also: SetIntVec, GetIntVec


Return to the main index