forked from Lephenixnoir/gint
122 lines
3.0 KiB
ArmAsm
122 lines
3.0 KiB
ArmAsm
/*
|
|
** gint:tmu:inth-tmu - Interrupt handlers for the timer units
|
|
** Perhaps the most technical of my interrupt handlers. They implement a
|
|
** simple kind of interrupt handler communication by letting the control flow
|
|
** from each interrupt handler to the next.
|
|
*/
|
|
|
|
/* Gates for the standard Timer Unit (TMU) */
|
|
.global _inth_tmu /* 128 bytes */
|
|
|
|
.section .gint.blocks, "ax"
|
|
.align 4
|
|
|
|
/* TMU INTERRUPT HANDLERS - 128 BYTES
|
|
Unfortunately I did not manage to write a handler that cleared the interrupt
|
|
flag and invoked a callback in less than 34 bytes data included. So I
|
|
decided to make several gates operate as a whole and add a bit more features
|
|
in them. Basically, these handlers:
|
|
- Clear the interrupt flag
|
|
- Invoke a callback function and pass it a user-provided argument
|
|
- Stop the timer if the callback returns non-zero
|
|
- Host their own callback pointers and arguments
|
|
|
|
It is important to notice that the code of the following gates looks like
|
|
they are contiguous in memory. The assembler will make that assumption, and
|
|
turn any address reference between two gates into a *relative displacement*.
|
|
If the gates don't have the same relative location at runtime, the code will
|
|
crash because we will have broken the references. This is why we can only do
|
|
it with handlers that are mapped to consecutive event codes. */
|
|
|
|
_inth_tmu:
|
|
|
|
/* FIRST GATE - TMU0 entry, clear underflow flag and call back */
|
|
_inth_tmu_0:
|
|
mova .storage0, r0
|
|
mov #0, r1
|
|
|
|
/*** This is the first shared section ***/
|
|
.shared1:
|
|
mov.l r8, @-r15
|
|
sts.l pr, @-r15
|
|
mov.l r1, @-r15
|
|
|
|
/* Load the TCR address */
|
|
mov.l .mask, r3
|
|
not r3, r4
|
|
mov.l @(8, r0), r1
|
|
|
|
/* Clear the interrupt flag */
|
|
1: mov.w @r1, r2
|
|
tst r4, r2
|
|
and r3, r2
|
|
mov.w r2, @r1
|
|
bf 1b
|
|
|
|
/* Prepare callback and jump to second section */
|
|
mov.l .gint_inth_callback, r8
|
|
bra .shared2
|
|
mov.l @r8, r8
|
|
|
|
/* SECOND GATE - TMU1 entry and stop timer */
|
|
_inth_tmu_1:
|
|
mova .storage1, r0
|
|
bra .shared1
|
|
mov #1, r1
|
|
|
|
/*** This is the second shared section ***/
|
|
.shared2:
|
|
/* Invoke callback */
|
|
mov.l @r0, r4
|
|
jsr @r8
|
|
mov.l @(4, r0), r5
|
|
|
|
/* Stop the timer if the return value is not zero */
|
|
mov.l @r15+, r5
|
|
tst r0, r0
|
|
bt 2f
|
|
mov.l .timer_stop, r4
|
|
jsr @r8
|
|
nop
|
|
|
|
2:
|
|
lds.l @r15+, pr
|
|
rts
|
|
mov.l @r15+, r8
|
|
|
|
.zero 2
|
|
|
|
/* THIRD GATE - TMU2 entry and storage for TMU0 */
|
|
_inth_tmu_2:
|
|
mova .storage2, r0
|
|
bra .shared1
|
|
mov #2, r1
|
|
|
|
.zero 10
|
|
|
|
.gint_inth_callback:
|
|
.long _gint_inth_callback
|
|
|
|
.storage0:
|
|
.long 0 /* Callback: Configured dynamically */
|
|
.long 0 /* Argument: Configured dynamically */
|
|
.long 0xa4490010 /* TCR0: Overridden at startup on SH3 */
|
|
|
|
/* FOURTH GATE - Storage for TMU1, TMU2 and other values */
|
|
_inth_tmu_storage:
|
|
|
|
.mask:
|
|
.long 0xfffffeff
|
|
.timer_stop:
|
|
.long _timer_stop
|
|
|
|
.storage1:
|
|
.long 0 /* Callback: Configured dynamically */
|
|
.long 0 /* Argument: Configured dynamically */
|
|
.long 0xa449001c /* TCR1: Overridden at startup on SH3 */
|
|
|
|
.storage2:
|
|
.long 0 /* Callback: Configured dynamically */
|
|
.long 0 /* Argument: Configured dynamically */
|
|
.long 0xa4490028 /* TCR2: Overridden at startup on SH3 */
|