2018-04-19 13:24:26 +02:00
|
|
|
//---
|
|
|
|
// gint - An alternative runtime environment for fx9860g and fxcg50
|
|
|
|
//---
|
|
|
|
|
|
|
|
#ifndef GINT_GINT
|
|
|
|
#define GINT_GINT
|
|
|
|
|
2021-06-13 18:13:09 +02:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
#include <gint/defs/types.h>
|
2021-04-20 13:52:18 +02:00
|
|
|
#include <gint/defs/call.h>
|
2020-11-04 22:12:01 +01:00
|
|
|
#include <gint/config.h>
|
2021-04-23 18:50:20 +02:00
|
|
|
#include <gint/intc.h>
|
2018-04-19 13:24:26 +02:00
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
/* gint_world_switch(): Switch out of gint to execute a function
|
2020-05-10 14:03:41 +02:00
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
This function can be used to leave gint, restore the OS's hardware state,
|
|
|
|
and execute code there before returning to gint. By doing this one can
|
|
|
|
effectively interleave gint with the standard OS execution. gint drivers
|
|
|
|
will be inactive during this time but OS features such as BFile or the
|
|
|
|
main menu are available.
|
2020-05-10 14:03:41 +02:00
|
|
|
|
2020-06-20 17:18:51 +02:00
|
|
|
This main uses for this switch are going back to the main menu and using
|
|
|
|
BFile function. You can go back to the main menu easily by calling getkey()
|
|
|
|
(or getkey_opt() with the GETKEY_MENU flag set) and pressing the MENU key,
|
|
|
|
or by calling gint_osmenu() below which uses this switch.
|
2020-05-10 14:03:41 +02:00
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
The code to execute while in OS mode is passed as a gint call; you can use
|
|
|
|
GINT_CALL() to create one. This allows you to pass arguments to your
|
|
|
|
function, as well as return an int.
|
|
|
|
|
|
|
|
@function A GINT_CALL() to execute while in OS mode
|
|
|
|
-> Returns the return value of (function), if any, 0 if function is NULL. */
|
|
|
|
int gint_world_switch(gint_call_t function);
|
|
|
|
|
|
|
|
/* This function is an older version of gint_world_switch() which only accepts
|
|
|
|
functions with no arguments and no return value. It will be removed in
|
|
|
|
gint 3. */
|
|
|
|
__attribute__((deprecated("Use gint_world_switch() instead")))
|
2020-05-10 14:03:41 +02:00
|
|
|
void gint_switch(void (*function)(void));
|
|
|
|
|
2022-05-15 20:16:03 +02:00
|
|
|
/* gint_world_sync(): Synchronize asynchronous drivers
|
|
|
|
|
|
|
|
This function waits for asynchronous tasks to complete by unbinding all
|
|
|
|
drivers. This is useful in certain hardware operations while remaining in
|
|
|
|
gint. */
|
|
|
|
void gint_world_sync(void);
|
|
|
|
|
2020-06-20 17:18:51 +02:00
|
|
|
/* gint_osmenu(): Call the calculator's main menu
|
2018-04-19 13:24:26 +02:00
|
|
|
|
2020-06-20 17:18:51 +02:00
|
|
|
This function safely invokes the calculator's main menu with gint_switch().
|
2018-04-19 13:24:26 +02:00
|
|
|
If the user selects the gint application again in the menu, this function
|
|
|
|
reloads gint and returns. Otherwise, the add-in is fully unloaded by the
|
|
|
|
system and the application terminates.
|
|
|
|
|
|
|
|
This function is typically called when the [MENU] key is pressed during a
|
2020-06-20 17:18:51 +02:00
|
|
|
call to getkey(), but can also be called manually. */
|
2020-05-10 14:03:41 +02:00
|
|
|
void gint_osmenu(void);
|
2018-04-19 13:24:26 +02:00
|
|
|
|
2022-09-02 22:29:19 +02:00
|
|
|
/* gint_osmenu_native(): Like gint_osmenu() without the world switch
|
|
|
|
This is a replacement for gint_osmenu() which can be used when the current
|
|
|
|
kernel is already the native OS kernel. */
|
|
|
|
void gint_osmenu_native(void);
|
|
|
|
|
2020-07-20 20:37:34 +02:00
|
|
|
/* gint_setrestart(): Set whether to restart the add-in after exiting
|
|
|
|
|
2022-09-02 22:29:19 +02:00
|
|
|
An add-in that returns from its main() function automatically exits to the
|
|
|
|
OS' main menu. However, when this happens the OS does not allow the add-in
|
|
|
|
to be restarted unless another add-in is launched first. (This is because
|
|
|
|
the OS tries to *resume* the current add-in, which then proceeds to exit
|
|
|
|
again immediately.)
|
2020-07-20 20:37:34 +02:00
|
|
|
|
2022-09-02 22:29:19 +02:00
|
|
|
This function enables a gint trick where after main() returns the add-in
|
|
|
|
will invoke the main menu with gint_osmenu() rather than exiting. If the
|
|
|
|
add-in is selected again, gint will jump back to the entry point, creating
|
|
|
|
the illusion that the add-in exited and was then restarted.
|
2020-07-20 20:37:34 +02:00
|
|
|
|
|
|
|
@restart 0 to exit, 1 to restart by using gint_osmenu() */
|
|
|
|
void gint_setrestart(int restart);
|
|
|
|
|
2021-04-23 18:50:20 +02:00
|
|
|
/* This function has been moved to the INTC driver */
|
|
|
|
__attribute__((deprecated("Use intc_handler() instead")))
|
|
|
|
static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
|
|
|
|
return intc_handler(code, h, size);
|
|
|
|
}
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2021-04-27 14:29:38 +02:00
|
|
|
/* gint_inth_callback(): Callback from interrupt handler to userland
|
2020-06-20 17:18:51 +02:00
|
|
|
|
2021-04-27 14:29:38 +02:00
|
|
|
This function performs an indirect call as with gint_call(), afters saving
|
|
|
|
the user context, enabling interrupts and going to user bank. This is useful
|
|
|
|
to call user code from interrupt handlers. You can think of it as a kernel-
|
|
|
|
space escape to virtualized userland during interrupt handling.
|
2020-06-20 17:18:51 +02:00
|
|
|
|
2021-04-27 14:29:38 +02:00
|
|
|
This function can only be useful in an interrupt handler's assembler code.
|
|
|
|
It is loaded at a runtime-determined address and accessed through a function
|
|
|
|
pointer, like this:
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
|
|
|
|
mov.l .callback, r0
|
|
|
|
mov.l @r0, r0 # because function pointer
|
2021-04-27 14:29:38 +02:00
|
|
|
mov <address of gint_call_t object>, r4
|
kernel: dynamic loading of GMAPPED functions to user RAM
This commit introduces a large architectural change. Unlike previous
models of the fx-9860G series, the G-III models have a new user RAM
address different from 8801c000. The purpose of this change is to
dynamically load GMAPPED functions to this address by querying the TLB,
and call them through a function pointer whose address is determined
when loading.
Because of the overhead of using a function pointer in both assembly and
C code, changes have been made to avoid GMAPPED functions altogether.
Current, only cpu_setVBR() and gint_inth_callback() are left, the second
being used specifically to enable TLB misses when needed.
* Add a .gint.mappedrel section for the function pointers holding
addresses to GMAPPED functions; add function pointers for
cpu_setVBR() and gint_inth_callback()
* Move rram to address 0 instead of the hardcoded 0x8801c000
* Load GMAPPED functions at their linked address + the physical address
user RAM is mapped, to and compute their function pointers
* Remove the GMAPPED macro since no user function needs it anymore
* Add section flags "ax" (code) or "aw" (data) to every custom .section
in assembler code, as they default to unpredictable values that can
cause the section to be marked NOLOAD by the linker
* Update the main kernel, TMU, ETMU and RTC interrupt handlers to use
the new indirect calling method
This is made possible by new MMU functions giving direct access to the
physical area behind any virtualized page.
* Add an mmu_translate() function to query the TLB
* Add an mmu_uram() function to access user RAM from P1
The exception catching mechanism has been modified to avoid the use of
GMAPPED functions altogether.
* Set SR.BL=0 and SR.IMASK=15 before calling exception catchers
* Move gint_exc_skip() to normal text ROM
* Also fix registers not being popped off the stack before a panic
The timer drivers have also been modified to avoid GMAPPED functions.
* Invoke timer_stop() through gint_inth_callback() and move it to ROM
* Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4)
* Remove the timer_clear() function by inlining it into the ETMU handler
(TCR is provided within the storage block of each timer)
* Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s
Additionally, VBR addresses are now determined at runtime to further
reduce hardcoded memory layout addresses in the linker script.
* Determine fx-9860G VBR addresses dynamically from mmu_uram()
* Determine fx-CG 50 VBR addresses dynamically from mmu_uram()
* Remove linker symbols for VBR addresses
Comments and documentation have been updated throughout the code to
reflect the changes.
2020-09-17 14:48:54 +02:00
|
|
|
jsr @r0
|
|
|
|
nop
|
|
|
|
.callback:
|
|
|
|
.long _gint_inth_callback
|
|
|
|
|
2021-04-27 14:29:38 +02:00
|
|
|
@call Address of a gint_call_t object
|
2020-06-20 17:18:51 +02:00
|
|
|
Returns the return value of the callback. */
|
2021-04-27 14:29:38 +02:00
|
|
|
extern int (*gint_inth_callback)(gint_call_t const *call);
|
2020-06-20 17:18:51 +02:00
|
|
|
|
2022-11-27 22:57:50 +01:00
|
|
|
/* gint_set_quit_handler(): Setup a call to be invoked when leaving the add-in
|
2022-11-20 11:36:57 +01:00
|
|
|
|
2022-11-27 22:57:50 +01:00
|
|
|
This function sets up the provided GINT_CALL() to be invoked when the
|
|
|
|
add-in is unloaded, which is either when we exit from main() or when
|
|
|
|
starting another application from the main menu. Crucially, this is only
|
|
|
|
*after* selecting an application, not before opening the main menu. The
|
|
|
|
quit handler is not invoked if the user re-enters the add-in.
|
2022-11-20 11:36:57 +01:00
|
|
|
|
2022-11-27 22:57:50 +01:00
|
|
|
This is based on the SetQuitHandler() syscall, and therefore the callback
|
|
|
|
runs in the OS world by default. If [run_in_os_world] is set to false, a
|
|
|
|
world switch will be performed to run the callback in the gint world.
|
|
|
|
|
|
|
|
TODO: Currently the quit handler is not called when exiting from main().
|
|
|
|
TODO: Detail how this interacts with destructor functions!
|
|
|
|
TODO: [run_in_os_world == false] is not honored yet (because unstable)
|
|
|
|
|
|
|
|
@call Callback to be performed when leaving add-in
|
|
|
|
@run_in_os_world true to stay in OS world, false to use gint world */
|
|
|
|
void gint_set_quit_handler(gint_call_t gcall, bool run_in_os_world);
|
2022-11-20 11:36:57 +01:00
|
|
|
|
2021-06-13 18:13:09 +02:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-04-19 13:24:26 +02:00
|
|
|
#endif /* GINT_GINT */
|