diff --git a/include/gint/intc.h b/include/gint/intc.h index 02f1de3..2f6c994 100644 --- a/include/gint/intc.h +++ b/include/gint/intc.h @@ -6,6 +6,7 @@ #define GINT_INTC #include +#include //--- // Interrupt names @@ -120,7 +121,7 @@ void *intc_handler(int event_code, void const *handler, size_t size); /* intc_handler_function(): Install a function as an interrupt handler This function can be used to install simple interrupt handlers. It installs - a pre-written interrupt handler that calls back the provided function. + a pre-written interrupt handler that performs the provided indirect call. Essentially it means that the interrupt handler can be written in C without the numerous constraints of intc_handler(), at the cost of always going back to userspace and a small time overhead. @@ -128,6 +129,6 @@ void *intc_handler(int event_code, void const *handler, size_t size); @event_code Identifier of the interrupt block @function Function to use as a handler Returns true on success, false if the event code is invalid. */ -bool intc_handler_function(int event_code, void (*function)(void)); +bool intc_handler_function(int event_code, gint_call_t function); #endif /* GINT_INTC */ diff --git a/src/intc/intc.c b/src/intc/intc.c index 1ca30cb..fe3bccf 100644 --- a/src/intc/intc.c +++ b/src/intc/intc.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -170,15 +172,17 @@ void *intc_handler(int event_code, const void *handler, size_t size) return memcpy(dest, handler, size); } -bool intc_handler_function(int event_code, void (*function)(void)) +bool intc_handler_function(int event_code, gint_call_t function) { - /* Install the genric handler */ + /* Install the generic handler */ extern void intc_generic_handler(void); void *h = intc_handler(event_code, intc_generic_handler, 32); if(!h) return false; - /* Set the function to be called */ - *(void **)(h + 24) = function; + /* Copy the call */ + memcpy(h + 8, &function, 20); + /* Copy the runtime address of gint_inth_callback() */ + *(void **)(h + 28) = gint_inth_callback; return true; } diff --git a/src/intc/inth.s b/src/intc/inth.s index 0556f20..9ba4aad 100644 --- a/src/intc/inth.s +++ b/src/intc/inth.s @@ -10,24 +10,10 @@ .align 4 _intc_generic_handler: - /* Create a GINT_CALL() object with no arguments */ - sts.l pr, @-r15 - add #-20, r15 - mov.l .function, r0 - mov.l r0, @r15 + mova 1f, r0 + mov.l 2f, r1 + jmp @r1 + mov r0, r4 - /* Call back to the function in userspace */ - mov.l .gint_inth_callback, r0 - mov.l @r0, r0 - jsr @r0 - mov r15, r4 - - add #20, r15 - lds.l @r15+, pr - rts - nop - -.function: - .long 0 /* Function, set when handler is installed */ -.gint_inth_callback: - .long _gint_inth_callback +1: .zero 20 /* Indirect call to be made */ +2: .long 0 /* Address of _gint_inth_callback at runtime */ diff --git a/src/rtc/rtc.c b/src/rtc/rtc.c index b24ebbe..427c0c9 100644 --- a/src/rtc/rtc.c +++ b/src/rtc/rtc.c @@ -164,7 +164,7 @@ static void configure(void) RTC->RCR2.PEF = 0; /* Install the RTC interrupt handler */ - intc_handler_function(0xaa0, rtc_periodic_interrupt); + intc_handler_function(0xaa0, GINT_CALL(rtc_periodic_interrupt)); /* Disable the RTC interrupts for now. Give them priority 1; higher priorities cause freezes when going back to the system on SH3 diff --git a/src/usb/usb.c b/src/usb/usb.c index 5cc737c..c2a00a3 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -169,7 +169,7 @@ int usb_open(usb_interface_t const **interfaces, gint_call_t callback) USB.NRDYENB.word = 0x0000; USB.BEMPENB.word = 0x0000; - intc_handler_function(0xa20, usb_interrupt_handler); + intc_handler_function(0xa20, GINT_CALL(usb_interrupt_handler)); intc_priority(INTC_USB, 15); usb_open_status = true;