Interrupts

Existing Tutorials:

|Joe Pemberton's Interrupts Guide for TI-83+ calculators
Note: Learn ASM in 28 days: day 23 Interrupts is inaccurate!

Introduction

Interrupts are exactly as their name states: They interrupt the operation of code to operate other code, occurring at fairly steady intervals. Using interrupts is a good way to keep track of time in games because they operate regardless of what other code is currently being executed. There are two kinds of interrupts: hardware and software. Software interrupts are triggered by the RST command, and won't be discussed in this tutorial. Examples of hardware interrupt use:
grey-scale
steady time counters
animated sprites
Animated Tile maps (similar to animated sprites)

Using interrupts

Enabling/Disabling

To enable interrupts, use the EI command. To disable interrupts, use the DI command.

Interrupt Modes

There are three different interrupt modes. To change the interrupt mode use the IM command. Each mode is triggered slightly differently or when triggered performs different actions.

Mode 0

We won't worry about mode 0, as TI-Calculators can't make use of this mode. In mode 0, interrupts are triggered by external hardware. However, since we can't connect external hardware to TI-Calculators, an interrupt is never triggered. You can test this with this code:

ei
im 0
halt ; captures the last interrupt from previous mode
halt ; captures the 1st interrupt generated in mode 0
im 1
ret

Note: It is very important not to return to the OS in mode 0! It will cause your calculator to crash. It's better in fact to not ever use mode 0, as if you want to turn off interrupts, use DI.

Mode 1

Mode 1 is the 'default' interrupt mode. It is triggered roughly every 0.007 seconds at a frequency of 140 Hz. It is used by the OS, and messing with this interrupt might not be a good idea. The OS uses it to update the run indicator (which is why it always moves at roughly the same speed), detect input (using GetKey/GetCSC), and various other OSy things.

Mode 2

Mode 2 is similar to Mode 1, as it is triggered in roughly the same frequency, except instead of calling a specific location, it jumps to theoretically any location in memory. This means that we can have it jump consistently to code we want executed every 0.007 seconds.

Setting up a Mode 2 Interrupt

How does a Mode 2 interrupt work? The answer is not so carefully. It retrieves a value from the I register, then the lower byte of the address is chosen at random. However, it gets worse. You'd think that'd be where it jumps to, but instead it loads the byte at that address as the MSB and the byte at the address after as the LSB and the interrupt jumps to that address. Confused yet?

Interrupt Jump Table

So how do we safely install a mode 2 interrupt? First, we need to identify a safe area of ram that has at least 257 bytes free. The location must be somewhere that the MSB of the address is constant (00,ドル 01,ドル…$FE). This will be our interrupt jump table.

Luckily for us, appbackupscreen is located from 9872ドル to 9ドルB72. So, if we take 9900ドル to 9ドルA00 inclusive, we'll have the necessary 257 bytes for our jump table.

Interrupt Location

Next, we need to identify an address like 0000,ドル 0101,ドル 0202,ドル…, $FFFF that is also safe to modify. This location will be the location of our interrupt. We'll write this value to every location in the Interrupt Jump Table, resulting in our interrupt being called all the time.

Again, appbackupscreen provides the perfect location for us to install our interrupt. 9ドルA9A satisfies all of the conditions mentioned above, and is well within the confines of appbackupscreen.

The Interrupt Code

What does the interrupt code look like? Well, it is completely identical to regular z80 code. Anything that can be executed normally can be executed from interrupt code. There are a few things you must do to make interrupt code not crash your calculator, though.

Shadow Registers

Since interrupt code is executed normally like regular code, it modifies the regular registers. A way to get around this to either not modify any registers (extremely hard, most instructions modify some flag or another), or to use shadow registers. Shadow registers are copies of the registers. There are not instructions that modify their values except the swap instructions (EX and EXX). It is common practice for interrupts to swap the registers as one of the first instructions.

interrupt:
; start of the interrupt code
; swap AF, BC, DE, and HL with their shadow registers
 ex AF,AF'
 exx

Returning

Interrupts return using the RET instruction. There are the RETI and RETN instructions, but they return from certain types of interrupts not available on TI calculators. Note that if you do put RETI or RETN at the end of an interrupt it will still return, but they cost 6 more T-states plus an additional byte, and so their use is discouraged.

Re-enabling interrupts

We wouldn't want another interrupt to be triggered while our interrupt code is being run, so the first thing to do when interrupt code is called is to disable interrupts with DI. To ensure that our interrupt will be executed again, we need to re-enable interrupts with EI at the end of our code.

interrupt:
; interrupt code
; ...
 ei
 ret

A Simple Interrupt

Here's a simple program that will install an interrupt that increases a 16-bit timer. It demonstrates most of the topics discussed above.

main:
 bcall(_ClrLCDFull)
; disable interrupts while we're install ours
 di
; set up the interrupt jump table to jump to 9ドルA9A
 ld a,9ドルA
 ld (9900ドル),a
 ld hl,9900ドル
 ld de,9901ドル
 ld bc,256
 ldir
; copy our interrupt to 9ドルA9A
 ld hl,interruptStart
 ld de,9ドルA9A
 ld bc,interruptEnd - interruptStart
 ldir
; set 99ドル into I
 ld a,99ドル
 ld I,a
; set interrupt mode 2
 im 2
loop:
; re-enable interrupts
 ei
; rest of our program
 ld hl,0
 ld (curRow),hl
 ld hl,(counter)
 bcall(_DispHl)
 jr loop
interruptStart:
; disable interrupts during our interrupt
 di
; swap registers
 ex AF,AF'
 exx
; our interrupt code
 ld hl,(counter)
 inc hl
 ld (counter),hl
; swap back registers
 ex AF,AF'
 exx
; re-enable interrupts and return
 ei
 ret
interruptEnd:
counter:
.dw 0

Interrupt Ports

Port 03ドル

Port 04ドル

Review

Conclusion

page revision: 10, last edited: 03 Apr 2009 23:37
Unless otherwise stated, the content of this page is licensed under GNU Free Documentation License.
Click here to edit contents of this page.
Click here to toggle editing of individual sections of the page (if possible). Watch headings for an "edit" link when available.
Append content without editing the whole page source.
Check out how this page has evolved in the past.
If you want to discuss contents of this page - this is the easiest way to do it.
View and manage file attachments for this page.
A few useful tools to manage this Site.
Change the name (also URL address, possibly the category) of the page.
View wiki source for this page without editing.
View/set parent page (used for creating breadcrumbs and structured layout).
Notify administrators if there is objectionable content in this page.
Something does not work as expected? Find out what you can do.
General Wikidot.com documentation and help section.
Wikidot.com Terms of Service - what you can, what you should not etc.
Wikidot.com Privacy Policy.

AltStyle によって変換されたページ (->オリジナル) /