Table of Contents (click on a link to jump to that web page)
- Part 1 – What is an IRQ and when would I use it?
- Part 2 – Overview with an example program
- Part 3 – Can my IRQ run without effecting BASIC?
- Part 4 – Simpler ways to use interrupts on the CoCo
- Part 5 – Advanced interrupt settings and using CoCo 3 specific interrupts
In this section I will be going over some pretty advanced techniques to speed up your interrupt request routine so it has minimal effect on the rest of your program.
First trick is to setup an FIRQ that is in Direct Page space. This will save a couple CPU Cycles every time the FIRQ is triggered.
The DP is set to $3E and the FIRQ routine starts in RAM at address $3ECA
LDA #$0E * Write the direct page JMP instruction LDB #$CA * Will jump to address DP + $CA = $3ECA in our example STD $010F * CoCo 1 & 2 FIRQ Jump pointer
Simon Jonassen told me about trick that you can use with the jump location in a CoCo 1 & 2. You can use the FIRQ jump Vector location as the actual interrupt routine so there is no jump required the code is executed at the FIRQ vector. To use this you would just put your entire FIRQ routine starting at $010F. That way you save the few extra cycles that would normally be used with the JMP $xxxx instruction. If your program doesn’t use the FIRQ you can do the same thing with the IRQ but your interrupt routine would start at $010c. – Thanks Simon
I’m going to show you some very optimized 6809 code that will be used for a CoCo 3 only audio sample player. This code is not CoCo 1 or 2 compatible.
In this example the audio data has been loaded in RAM starting at address $3D59 and ending at address $7FFF and this code will playback the sample looping it over and over.
To minimize the CPU cycles this interrupt routine uses some self modifying code.
ORG $C000 * Address of the Direct Page and FIRQ DirectPage: SETDP DirectPage/256 * Setup the DP addressing for the assembler ***************************************** * Play Sample in the background in mem $3D59-$7FFF, Loop it Sample1Start: FDB $3D59 * location where sample starts counting down from, used for looping FIRQ_Interrupt1: STA FIRQRestoreA+1 * Save A before we exit the routine (self modifying code) LDA FIRQENR * Re enable the FIRQ LoadAudio1: LDA $3D59 * This value gets changed with some self modifying code below STA $FF20 * OUTPUT sound to DAC INC LoadAudio1+2 * Increment the LSB of Sample pointer BNE > * check if we hit 00, if not exit INC LoadAudio1+1 * Increment the MSB of Sample pointer BPL > * If positive then we are good still under $8000 otherwise (end of sample, reset pointer) Hit8000: * Restore the pointer to the start location of the sample LDA Sample1Start * Point to the MSB of the sample Start location STA LoadAudio1+1 * Store the MSB of Sample pointer LDA Sample1Start+1 * Point to the LSB of the sample Start location STA LoadAudio1+2 * Store the LSB of Sample pointer FIRQRestoreA: ! LDA #$00 * STA at the start of the FIRQ stores A's value here and gets loaded before the RTI saves a cycle and a byte of RAM RTI * Return from the FIRQ
The program starts here and sets up the hardware on the CoCo 3 to use the GIME chip’s interrupts. This is different from the previous methods shown in this series of posts.
START *********************************************************** ORCC #$50 * Disable interrupts CLR $FFD9 * High Speed mode enabled SETDP DirectPage/256 * Set the direct Page so the assembler will use Direct Page addressing when assembling LDA #DirectPage/256 * Set the Direct Page value TFR A,DP * to where our FIRQ is located LDA #%00110100 * Setup the CoCo 3's hardware STA $FF01 * HSYNC IRQ Disabled, IRQ Polarity Flag falling Edge, Data Direction Normal, Select Line LSB = 0, HSYNC Flag = 0 STA $FF03 * VSYNC IRQ Disabled, IRQ Polarity Flag falling Edge, Data Direction Normal, Select Line MSB = 0, VSYNC Flag = 0 STA $FF21 * CONTROL OF CD FIRQ* TO CPU DISABLED, IRQ Polarity Falling Edge of CD, CD Flag off STA $FF23 * CONTROL OF Cart FIRQ* TO CPU DISABLED, IRQ Polarity Falling Edge of Cart, Cart Flag off LDA #%01111100 * STA $FF90 * CoCo 3 Mode, MMU Enabled, GIME IRQ Enabled, GIME FIRQ Enabled, Vector RAM at FEXX enabled, Standard SCS Normal, ROM Map 16k Int, 16k Ext LDA #%00100000 * STA $FF91 * Mem Type 64k chips, 279.365 nsec timer, MMU Task 0 - $FFA0-$FFA7 LDA #%10000000 * STA $FF98 * Graphics mode, Colour output, 60 hz, max vertical res * Setup the Timer FIRQ LDA #$0E * Write the JMP instruction to a direct page JMP location LDB #FIRQ_Interrupt1-DirectPage * B now is the address of the FIRQ routine STD $FEF4 * Save it to the CoCo 3 FIRQ vector address LDD #$0280 * STD $FF94 * Set countdown Timer to $0280 - This is the speed the samples will playback at LDA #%00100000 * $20 STA $FF93 * Enable TIMER FIRQ Interrupt ANDCC #$AF * = %10101111 this will Enable the IRQ and the FIRQ to start * Your program can go here, for now it just loops forever as the sample plays in the background ! BRA < END START * Tell the assembler when creating an DECB ML program to set the 'EXEC' address to wherever the label START is in RAM (above)
I hope you are now an interrupt expert and use them in your next awesome game… 🙂