Interrupts
Two routines GetIntVec
and SetIntVec
are dedicated to managed the standard vectors for interrupts. You can use them to setup you own interrupt handlers and to restore the previous interrupts handlers.
The presence of the OS ROM during interrupts handling is required for proper operation of the following routines and code examples. So if you want disable the OS ROM, you have to use $DEFINE ROMOFF, to ensure properly setup OS interrupts vectors and handlers.
If we have disabled the OS ROM using {$define romoff}
and are calling routines placed in the memory area $C000..$FFFF
we must take care to set PORTB
properly.
procedure NewInterrupt; interrupt; assembler;
asm
dec portb // Disable the OS ROM
jsr user_proc_c000_ffff // Call routine in RAM under the OS ROM
inc portb // Enable the OS ROM
... // Interrupt-specific return logic, see below
end;
NMIs - VBL, DLI
GetIntVec
GetIntVec(iVBLI, pointer); // Get the address of the immediate vertical blank interrupt handler (VVBLKI, $0222)
GetIntVec(iVBLD, pointer); // Get the address of the deferred vertical blank interrupt handler (VVBLKD, $0224)
GetIntVec(iDLI, pointer); // Get the address of the display list interrupt handler (VDSLST, $0200)
var oldVBL: pointer;
begin
GetIntVec(iVBLD, oldVBL); // Remeber old vector to restore it later
end.
SetIntVec
SetIntVec(iVBLI, pointer); // Set the address of the immediate vertical blank interrupt handler (VVBLKI, $0222)
SetIntVec(iVBLD, pointer); // Set the address of the deferred vertical blank interrupt handler (VVBLKD, $0224)
SetIntVec(iDLI, pointer); // Set the address of the display list interrupt handler (VDSLST, $0200)
Immediate Vertical Blank Interrupt
The VBLI (vertical blank immediate) interrupt handler is terminated by jumping to the SYSVBV
address ($E45F). It will perform the standard tasks of the immediate vertical blank interrupt and restore the values of the A
, X
, Y
CPU6502 registers from the stack before it returns.
procedure NewVBLI; interrupt; assembler;
asm
jmp sysvbv
end;
begin
SetIntVec(iVBLI, @NewVBLI);
end.
Deferred Vertical Blank Interrupt
The VBLD (vertical blank deferred) interrupt handler is terminated by jumping to the XITVBV
address ($E462) which will restore the value of the A
, X
, Y
CPU6502 registers from the stack before it returns.
procedure newVBLD; interrupt; assembler;
asm
// Your code
jmp xitvbv
end;
begin
SetIntVec(iVBLD, @newVBLD);
end.
Display List Interrupt
As opposed to the vertical blank interrupt handler, which save the values of the A
, X
, Y
CPU6502 registers before the interupt vector is called, the display list interrupt handler only saves the A
CPU6502 register to the stack. Therefore the iDLI (display list) interrupt handle is termianted with single PLA
instruction.
procedure NewDLI; interrupt; assembler;
asm
// Your code
pla
end; // Will become RTI
begin
SetIntVec(iDLI, @NewDLI);
end.
IRQs - TIMER1, TIMER2, TIMER4
GetIntVec
GetIntVec(iTIM1, pointer); // Get the address of the TIMER 1 interrupt handler (VTIMR1, $0210)
GetIntVec(iTIM2, pointer); // Get the address of the TIMER 2 interrupt handler (VTIMR2, $0212)
GetIntVec(iTIM4, pointer); // Get the address of the TIMER 4 interrupt handler (VTIMR4, $0214)
var oldIRQ: pointer;
begin
GetIntVec(iTIM4, oldIRQ);
end.
SetIntVec
SetIntVec(iTIM1, pointer); // Set the address of the TIMER 1 interrupt handler (VTIMR1, $0210)
SetIntVec(iTIM2, pointer); // Set the address of the TIMER 2 interrupt handler (VTIMR2, $0212)
SetIntVec(iTIM4, pointer); // Set the address of the TIMER 4 interrupt handler (VTIMR4, $0214)
procedure TimerIRQ; assembler; interrupt;
asm
// Your code
pla
end; // Becomes RTI
begin
SetIntVec(iTIM4, @TimerIRQ, 0, 28);
repeat until keypressed;
SetIntVec(iTIM4, oldIRQ);
end.
When the system executes a jump to an IRQ interrupt handler, it puts the contents of the accumulator on the stack beforehand.
Keep this in mind and end the interrupt handler with a single PLA
instruction.
Additional parameters are required to trigger a new IRQ interrupt, such as the choice of base clock clock_base = [0,1]
and frequency rate = [6.255]
.
Values of rate
less than 6
will cause the system to slow down severely, up to a possible suspension.
SetIntVec(iTIM1, pointer, clock_base, rate);
SetIntVec(iTIM2, pointer, clock_base, rate);
SetIntVec(iTIM4, pointer, clock_base, rate);