DGRAY_PUSH_ON/OFF will push the current gray engine state to a stack
before transitioning to on/off mode. DGRAY_POP will later recover the
saved state and transition back to it.
* Define dgray() to replace gray_start() and gray_stop()
* Introduce a mechanism to override the d*() functions rather than using
another set of functions, namely g*(). Gray rendering should now be
done with d*() (a compatibility macro for g*() is available until v2.1).
* Gray engine now reserves TMU0 at the start of the add-in to prevent
surprises if timers are exhausted, so it nevers fails to start
* Replace other gray engine functions with dgray_*()
* More general rendering functions (in render/) to lessen the burden of
porting them to the gray engine. As a consequence, dtext_opt(),
dprint_opt() and drect_border() are now available in the gray engine,
which was an omission from 230b796.
* Allow C_NONE in more functions, mainly on fx-CG 50
* Remove the now-unused dupdate_noint()
Since both platforms now have their VBR and gint-specific data loaded
along the add-in's data, the .gint.data section is entirely unused.
The .gint.bss section is still used for uninitialized objects (it has
different semantics than .bss which is initially cleared) and the
.gint.data.sh3 and .gint.bss.sh3 sections that are dropped on the
SH4-only fx-CG 50 are also still used.
This change puts an end to the illegal occupation of some random RAM
area, solving most of the return-to-menu issues, including (but not
limited to) random key presses, multiple return, and VBR being
overwritten.
There are still known return-to-menu issues on SH3 (mainly just
GetKeyWait() returning immediately to gint probably due to multiple
KEY_CTRL_MENU being injected), but nothing crashy.
This change moves interrupt handler from VBR + 0x640 to VBR + 0x200, in
the gap between the exception and TLB miss handlers.
This new scheme is not limited to VBR+0x200 .. VBR+0x400 as new large
block numbers can be used to jump over the TLB miss handler and the
interrupt handler entry points.
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.
* Reduce the keyboard queue size from 64 to 32, which is more than
enough even for real-time games with multiple key presses.
* Pack the driver_event_t structure of the keyboard driver to make it 4
bytes rather than 6 bytes. Combined with the previous item, this saves
256 bytes off the BSS section (which is 3% of the SH3's static RAM).
* As part of a debugging attempt, updated the watchdog delay code in
iokbd_delay() to make it usable in the current version of gint.
* Restored port registers more aggressively in iokbd_row().
This change adds optimized versions of the core memory functions,
relying on 4-alignment, 2-alignment, and the SH4's unaligned move
instruction to (hopefully) attain good performance in all situations.
This change adds a new HWCALC model, HWCALC_FXCG_MANAGER, which
identifies Casio's official fx-CG Manager software. Both the Prizm and,
to my surprise, the fx-CG Manager use the old RAM address of 88000000
(P1) and a8000000 (P2) instead of the new fx-CG 50 address of 8c000000
(P1) and ac000000 (P2).
The VRAM is hence adjusted at startup to move hardcoded pointers into
the proper space. Added to the kernel moving the VBR space dynamically
on the Prizm, this allows gint to be fully compatible with these
platforms.
The fx-CG Manager is detected by its product ID made of 0xff.
Also adds a proper interface to the R61524 driver, even though it's not
any more complete than previously, and fixes an oversight where the
HWURAM entry of the kernel data array was no longer computed since the
TLB management change.
As of now, the fx-CG Manager still has a bug regarding return-to-menu
since returning from the main menu doesn't work very well and often
loops. This has been seen occasionally on some Graph 90+E so it's
unlikely to be a platform-specific problem.
This commit minimally changes the signature of timer_setup() to greatly
simplify timer management, allowing to user to let the library choose
available timers dynamically depending on the settings.
Gray quality is better on the Graph 35+E II, it still flickers a lot on
other models (as I remembered). There might be better settings out there
but I'm not sure we can reach the quality of the current Graph 35+E II
defaults. The Graph 75+E with which I tested might also be different
from other T6K11 such as the smaller Graph 35+E.
* Removed .pretext sections since the TLB is now entirely dynamic; left
only .text.entry for the start symbol.
* Reworked the main files of src/core to move the INTC to its own driver
and let the kernel handle only VBR space and CPU (now: VBR & CPUOPM).
* Moved src/core/gint.c to src/core/kernel.c and centralized all driver
loops that save or restore context for more robustness. This leaves
the callbacks of cpu_setVBR() (formerly gint_setvbr()) pretty short.
* Coalesced gint_switch_out() and gint_switch_in() into a single
function callback for cpu_setVBR().
* Added an abstraction of interrupt signals as an enumerated value so
that drivers no longer hardcode the IPR and IMR numbers and bits,
sometimes even with isSH3() due to differences in the SH7705.
* Changed the interrupt blocking method in cpu_setVBR() from SR.BL=1 to
SR.IMASK=15 so that TLB misses are still handled. This removes the
need for callback functions to be GMAPPED.
* Moved gint_osmenu() and its utilities to a new file src/core/osmenu.c.
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 introduces two new functions dtext_opt() and dprint_opt()
that have both color and alignment options. The regular dtext() and
dprint() have been changed to always used bg=C_NONE which is what most
calls want.
This change removes the RRAM region which was inherited from the fx9860g
memory layout but no longer relevant on fxcg50. This removed one
occurrence of a hardcoded user stack address in the linker script, the
other being the VBR address. But since the VBR only contains
position-independent code that is manually "relocated" at startup, the
linker script needs not actually use its value, so this is not a true
dependency.
gint should now more or less be able to boot up on an fxcg20, except for
the hardcoded VRAM addresses which need to be moved to the fxcg20 system
stack.
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 change ports the TLB management system to fx9860g through %003.
This raises the size limit for add-ins to about 500k.
Because SH3 fx9860g does not have ILRAM, the GMAPPED attribute has been
made to generate content to a .gint.mapped section which is sent to the
P1 RAM section historically dubbed "real ram" in which gint's data and
VBR are installed. (Now that I think about it, gint's data should try to
go to normal RAM instead to reduce pressure on this invasion.)
Return-to-menu was also fixed on both platforms by narrowing down the
need for code to remain mapped to the chance of running it with
interrupts disabled. The natural distribution of GMAPPED under this
criterion showed that _gint_setvbr had been left under TLB control;
moving it to the proper RAM area fixed gint switches.
Finally, an omission in the bound checks for mappable TEA addresses (TEA
>= 0x00300000) prevented the appearance of a non-interactible System
ERROR popup when some unmapped addresses are accessed.
This version still does not enable interrupts in timer callbacks,
exposing any application to a crash if a timer underflows while its
callback is not mapped. It is not suitable for any stable application!
This change adds a TLB miss handler that calls __TLB_LoadPTEH() and
removes the startu mapping of add-in pages in the explore() routine of
src/core/start.c.
Note that calling __TLB_LoadPTEH() manually might unexpectedly lead to a
TLB multihit problem as the requested page might be accidentally loaded
by a TLB miss in the code that loads it. A TLB multihit is a platform
reset, so this function should always be considered unsafe to call
(unless the calling code is in a combination of P1 space and ILRAM).
This change also moves a lot of functions out of the .pretext section,
notably topti, as this was designed to allow panic messages when the
add-in couldn't be mapped entirely. By contrast, a GMAPPED macro has
been defined to mark crucial kernel code and data that must remain
mapped at all times. This currently puts the data in ILRAM because
static RAM is not executable. An alternative will have to be found for
SH3-based fx9860g machines.
This version still does not allow TLB misses in timer callbacks and
breaks return-to-menu in a severe way! It is not suitable for any
stable application!
This change modifies the fx-CG 50 linker script to allow add-ins up to
2M and no longer complains about add-ins that don't fit in the TLB.
It also exposes the __TLB_LoadPTEH() syscall (%003 on fx9860g, %00c on
fxcg50) that answers TLB misses. This syscall can be called manually
from an add-in to load some pages and seems to work without problem.
However, this version does not provide any automatic TLB management,
some key areas of the kernel are still under TLB and some user code
(such as timer callbacks) is not! This version is suitable only for
add-ins smaller than 220k!
When parsing a %% format, the second % character was mistakenly not
skipped over after emitting a '%' output; this resulted in it being
treated as a format specifier. For instance,
printf("%%d", 12);
would print "%12".
A missing coordinate check in gint_dhline() would allow lines entirely
out of bounds of the screen to write pixels outside of their expected
range, often wrapping up to the next line, but possibly overflowing from
VRAM.
This commit improves the stability of gint_switch() in two ways:
1. Wait for hardware availability every time driver contexts are saved
or reloaded; this solves crashes due to DMA use when gint takes
control after a BFile call, since BFile_Create() (and possibly
BFile_Write()) leave the DMA running after returning.
2. Remap the add-in after a switch, as apparently calling BFile
functions causes some pages to be evicted. This is more noticeable on
fxcg50 when the size of add-ins nears 220k.
Additionally, dma_transfer_wait() has been updated to not sleep() unless
it is certain that the conditions for wakeup are fulfilled, as this
would sometimes freeze.
For some reason these syscalls tend to crash in a basic delete, create,
open, write, close workflow (after the write is finished). I'll look
into using the new gint/fxlib switch to use them safely.
This is a first version of gint_osmenu() on Graph 90+E. It works on the
same basis as the mono version, with the caveat that the automatic VRAM
display done by the system is terrible because of the reduced resolution
and status bar. Disabling any of this requires taking back control
earlier, which would make the whole GetKeyWait() method obsolete.
Tried the special key processing syscall, but it crashes upon return in
the add-in even before the fxlib code finishes. Maybe try later.
The unload() function is not very relevant for drivers because hardware
state is managed by ctx_save() and ctx_restore() and software state is
managed by underlying drivers when there are dependencies.
For now, it's been replaced with a wait() function that allows drivers
to not be interrupted at any point. It is currently used by the DMA to
wait for ongoing transfers to finish before disabling interrupts (which
would prevent the transfer end from being detected) and switching in and
out of gint.
* Add the gint_switch() function which executes user-provided code from
the system (CASIOWIN) context.
* Added interrupt masks to the core context (should have been there long
ago).
* Added the gint_osmenu() function that switches out of gint to invoke
GetKeyWait() and inject KEY_CTRL_MENU to trigger the main menu. This
uses many CASIOWIN syscalls, but we don't care because gint is unloaded.
Trickery is used to catch the key following the return in the add-in
and/or display a new application frame before GetKeyWait() even finishes
after coming back. This is only available on fx9860g for now.
* Removed any public syscall definition to clear up interfaces.
* Patched the DMA interruption problem in a weird way on fxcg50, a
driver function will be used to do that properly eventually.
* Changed the driver model to save driver contexts in preallocated
spaces instead of on the stack for overall less risk.
* Enabled return-to-menu with the MENU key on fx9860g in getkey().
* Changed the keyboard driver to emit releases before presses, as a
return-to-menu acts as a press+release of different keys in a single
driver frame, which confuses getkey().
* Fixed a really stupid bug in memcpy() that made the function really
not work.
Improvements in the timer driver:
* Expose ETMU modules as SH7705_TMU and SH7305_TMU in <gint/mpu/tmu.h>.
* Remove the timer_t structures, using SH*_ETMU and SH*_TMU instead.
Only interrupt gate entries are left hardcoded.
* Discovered that not only every write to the TCNT or TCR of an ETMU
takes about 1/32k of a second (hinting at registers being powered by
the same clock as the timer), but every write occuring while a previous
write is pending is *lost*. This led to terrible bugs when switching
ETMU contexts too fast in gint_switch().
* Removed an internal timer_address() function.
* Overall simplified the handling of timers and the initialization step.
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.
t6k11: use the gint array for variant detection
r61524: use true triple buffering by default
display: define DWIDTH and DHEIGHT
display: add C_RGB(r,g,b) (0 ≤ r,g,b ≤ 31) [fxcg50]