summaryrefslogtreecommitdiff
path: root/interrupts.asm.m4
diff options
context:
space:
mode:
Diffstat (limited to 'interrupts.asm.m4')
-rw-r--r--interrupts.asm.m4112
1 files changed, 112 insertions, 0 deletions
diff --git a/interrupts.asm.m4 b/interrupts.asm.m4
new file mode 100644
index 0000000..cf2b195
--- /dev/null
+++ b/interrupts.asm.m4
@@ -0,0 +1,112 @@
+;;; interrupt handling code
+
+ ;; Current interrupt mode. IM 1 and friends will modify
+ ;; this, it can be any of 0, 1, 2.
+int_mode: dc.b 0
+
+ ;; 0 if the emulated device doesn't want interrupts.
+ ;; 1 if interrupts are turned on.
+int_enabled: dc.b 1
+
+
+ ;; In interrupt mode 0, an interrupt will force a byte onto
+ ;; the data bus for the processor to execute. To handle
+ ;; those, the emulator will store the bus byte in int_opcode,
+ ;; which is followed by an absolute jump to the "next
+ ;; instruction". The value of int_jump will then be
+ ;; &int_opcode.
+ ;;
+ ;; This differs slightly from what I understand to be actual
+ ;; handling. The hardware will fetch an immediate argument to
+ ;; the interrupting instruction from the next location in
+ ;; memory.
+ ;;
+ ;; This emulator, on the other hand, will fetch the immediate
+ ;; argument from the JP instruction in the shim, and then
+ ;; dance off into la-la land.
+int_opcode: dc.b 0
+ dc.b $c3 ; JP immed.w
+int_return: dc.w 0 ; the destination address
+
+
+ ;; This is the interrupt routine. It can come at any point
+ ;; during an instruction, though routines that use a5 (e.g. by
+ ;; calling C subroutines) will have to turn off interrupts.
+ ;; Routines that call into TIOS will have to remove this
+ ;; interrupt handler.
+int_handler:
+ sub.l #4,a5
+ rte
+
+
+int_nevermind:
+ rts
+do_interrupt:
+ ;; todo: make this file m4'd
+ add.l #INT_OFFSET,a5 ; clear the interrupt flag
+
+ tst.b int_enabled ; 4 cycles
+ beq.b int_nevermind ; 8 cycles not taken
+ ;; Common case: interrupts enabled, fall through
+
+ ;; Since this is an instruction all its own, we have D0, D1,
+ ;; and D2 available.
+
+ pop.l a0
+
+ ;; Interrupts are most often in mode 1, then mode 2, and
+ ;; almost never in mode 0.
+ move.b int_mode,d0
+ cmpi.b #1,d0
+ beq int_do_mode2
+ cmpi.b #2,d0
+ beq int_do_mode1
+ cmpi.b #1,d0
+ beq int_do_mode0
+ jmp (a0)
+
+ ;; This routine emulates a mode 0 interrupt.
+
+ ;; IM 0: A byte is placed on the bus and executed as if it
+ ;; were inline in the program. This emulator will put that
+ ;; byte into int_opcode and set epc (or int_jump) to point
+ ;; there.
+int_do_mode0:
+ rts
+
+ ;; This routine emulates a mode 1 interrupt.
+
+ ;; IM 1: RST 38 is executed on every interrupt. This is what
+ ;; the TI-83+ uses almost all the time.
+int_do_mode1:
+ jmp emu_op_ff
+
+
+ ;; This routine emulates a mode 2 interrupt.
+
+ ;; IM 2: Vectored, the address jumped to is as follows:
+ ;;
+ ;; (I << 8) | (byte & 0xfe)
+ ;;
+ ;; where I is the I register, and byte is the byte that was
+ ;; found on the bus.
+int_do_mode2:
+ rts
+
+ ;; This routine emulates a non-maskable interrupt.
+int_do_nmi:
+ rts
+
+
+
+
+ ;; This routine is used by the emulated DI instruction, which
+ ;; turns off emulator interrupts.
+ints_stop:
+ rts
+
+ ;; This routine is used by the emulated EI instruction, which
+ ;; turns on emulator interrupts.
+ints_start:
+ rts
+