I have recenty discovered that the so-called "rram" section used by gint
to store its VBR space and a couple memory structures gets overwritten
when returning to the main menu. It is thus necessary to get rid of it
and store that data somewhere else.
My current lead is to have it at the start of the static RAM by querying
its address in the TLB. However, the static RAM is very small on SH3
(8k) so the VBR must be made more compact.
This change elaborates the event code translation scheme used on SH3 to
emulate SH4 event codes. It is now used to translate the event codes to
a gint-specific VBR layout that leaves no gaps and thus reduces the size
of the VBR space. The gint_inthandler() method has to be modified for
every new SH3 interrupt to maintain this scheme.
This change includes three reliability improvements in handlers:
1. TMU handlers now actively check for the UNF flag to go low rather
than expecting it to do so right away.
2. CPUOPM.INTMU is now set so that IMASK it updated at every interrupt
(which is absolutely required for nested interrupts!).
3. gint_inth_callback() no longer performs transfers between user bank
and kernel bank while in user bank, because this is when interrupts
are enabled and thus likely to corrupt the kernel bank; rather, it
now does it while in kernel bank with interrupts disabled.
This change fixes a never-should-have-worked problem where the ETMU
interrupt handler loses track of the timer ID before attempting to call
timer_stop(), resulting in complete nonsense.
And also a similar problem in timer_wait().
This change enables interrupts within timer callbacks, making it
possible to load pages to MMU while handling a timer underflow. The call
to TLB_LoadPTEH() has been moved directly into the VBR handler to avoid
jumping to ILRAM for a short call on SH4.
The TMU and ETMU handlers have been changed to callback through a new
function gint_inth_callback() that saves the user bank and a few
registers, then invokes the callback with interrupts enabled and in user
bank; until now, callbacks were invoked with interrupts disabled and in
kernel bank. Note that IMASK is still set so a callback can only be
interrupted by a high-priority interrupt.
A timer_wait() function has also been added to simplify tests that
involve timers. Finally, the priority level of the TMU0 underflow
interrupt has been set to 13 (as per the comments) instead of 7.
This version is the first stable version that handles TLB misses
transparently for large add-ins. It is suitable for every gint
application.
This is an obvious requirement for the interrupt routine, which was
forgotten and only surfaced when I used a timer callback started with
multiplications in an innocent add-in. r0..r7 are saved automatically,
which leaves pr, gbr, mach et macl susceptible to corruption by the
interrupt handler.
This commit introduces three timer driver changes:
* Export the definitions of the timer structures to a detailed header at
<gint/mpu/tmu.h>, and re-use them in the driver.
This integration is still limited as the driver keeps its own address
definitions and event codes.
* Clean the timer stop routine that is used in the interrupt handler. Up
until now the interrupt handler would only stop TSTR, which is not
enough to cleanly leave the timer (need TCOR=TCNT=-1) and is not even
sound with respect to gint's semantics as UNIE stays enabled so the
timer is not made available again.
The interrupt handler now calls into C code when the timer stop
condition is met (callback returns non-zero) to keep this clean. This
unsurprisingly solves problems that occurred in certain situations
when a timer was used repeatedly.
* Expose timer addresses using a timer_address() function, compensating
for the lack of address definitions in <gint/mpu/tmu.h>. This
interface is likely to evolve in the future to better integrate the
address in the MPU headers and move them out of the driver.