Changes in the driver and world system:
* Rewrite driver logic to include more advanced concepts. The notion of
binding a driver to a device is introduced to formalize wait(); power
management is now built-in instead of being handled by the drivers
(for instance DMA). The new driver model is described in great detail
in <gint/drivers.h>
* Formalized the concept of "world switch" where the hardware state is
saved and later restored. As a tool, the world switch turns out to be
very stable, and allows a lot of hardware manipulation that would be
edgy at best when running in the OS world.
* Added a GINT_DRV_SHARED flag for drivers to specify that their state
is shared between worlds and not saved/restored. This has a couple of
uses.
* Exposed a lot more of the internal driver/world system as their is no
particular downside to it. This includes stuff in <gint/drivers.h>
and the driver's state structures in <gint/drivers/states.h>. This is
useful for debugging and for cracked concepts, but there is no
API stability guarantee.
* Added a more flexible driver level system that allows any 2-digit
level to be used.
Feature changes:
* Added a CPU driver that provides the VBR change as its state save.
Because the whole context switch relied on interrupts being disabled
anyway, there is no longer an inversion of control when setting the
VBR; this is just part of the CPU driver's configuration. The CPU
driver may also support other features such as XYRAM block transfer
in the future.
* Moved gint_inthandler() to the INTC driver under the name
intc_handler(), pairing up again with intc_priority().
* Added a reentrant atomic lock based on the test-and-set primitive.
Interrupts are disabled with IMASK=15 for the duration of atomic
operations.
* Enabled the DMA driver on SH7305-based fx-9860G. The DMA provides
little benefit on this platform because the RAM is generally faster
and buffers are ultimately small. The DMA is still not available on
SH3-based fx-9860G models.
* Solved an extremely obnoxious bug in timer_spin_wait() where the
timer is not freed, causing the callback to be called when interrupts
are re-enabled. This increments a random value on the stack. As a
consequence of the change, removed the long delays in the USB driver
since they are not actually needed.
Minor changes:
* Deprecated some of the elements in <gint/hardware.h>. There really is
no good way to "enumerate" devices yet.
* Deprecated gint_switch() in favor of a new function
gint_world_switch() which uses the GINT_CALL abstraction.
* Made the fx-9860G VRAM 32-aligned so that it can be used for tests
with the DMA.
Some features of the driver and world systems have not been implemented
yet, but may be in the future:
* Some driver flags should be per-world in order to create multiple
gint worlds. This would be useful in Yatis' hypervisor.
* A GINT_DRV_LAZY flag would be useful for drivers that don't want to
be started up automatically during a world switch. This is relevant
for drivers that have a slow start/stop sequence. However, this is
tricky to do correctly as it requires dynamic start/stop and also
tracking which world the current hardware state belongs to.
* Add the power management functions (mostly stable even under
overclock; requires some testing, but no known issue)
* Add a dynamic configuration system where interfaces can declare
descriptors with arbitrary endpoint numbers and additional
parameters, and the driver allocates USB resources (endpoints, pipes
and FIFO memory) between interfaces at startup. This allows
implementations of different classes to be independent from each
other.
* Add responses to common SETUP requests.
* Add pipe logic that allows programs to write data synchronously or
asynchronously to pipes, in a single or several fragments, regardless
of the buffer size (still WIP with a few details to polish and the
API is not public yet).
* Add a WIP bulk IN interface that allows sending data to the host.
This will eventually support the fxlink protocol.
This mechanism allows callbacks to be defined with up to 4 32-bit
arguments, and could be extended later. This will hopefully replace the
timer_callback_t used in timers and RTC, and will be added to the DMA
and USB APIs -- the hard part is to not break source compatibility with
previous versions.
The new allocator uses a segregated best-fit algorithm with exact-size
lists for all sizes between 8 bytes (the minimum) and 60 bytes, one list
for blocks of size 64-252 and one for larger blocks.
Arenas managed by this allocator have built-in statistics that track
used and free memory (accounting for block headers), peak memory, and
various allocation results.
In addition, the allocator has self-checks in the form of integrity
verifications, that can be enabled with -DGINT_KMALLOC_DEBUG=1 at
configuration time or with the :dev configuration for GiteaPC. This is
used by gintctl.
The kmalloc interface is extended with a new arena covering all unused
memory in user RAM, managed by gint's allocator. It spans about 4 kB on
SH3 fx-9860G, 16 kB on SH4 fx-9860G, and 500 kB on fx-CG 50, in addition
to the OS heap. This new arena is now the default arena for malloc(),
except on SH3 where some heap problems are currently known.
This change introduces a centralized memory allocator in the kernel.
This interface can call into multiple arenas, including the default OS
heap and planned arenas managed by a gint algorithm.
The main advantage of this method is that it allows the heap to be
extended over previously-unused areas of RAM such as the end of the
static RAM region (apart from where the stack resides). Not using the OS
heap is also sometimes a matter of correctness since on some OS versions
the heap is known to fragment badly and degrade over time.
I hope the deep control this interfaces gives over meomry allocation
will allow very particular applications like object-specific allocators
in fragmented SPU memory.
This change does not introduce any new algorithm or arena so programs
should behave exactly as before.
The new keyboard device (keydev) interface implements the kernel's view
of a keyboard providing input events. Its main role is to abstract all
the globals of the KEYSC driver and getkey functions into a separate
object: the "keyboard device".
The device implements event transformations such as modifiers and
repeats, instead of leaving them to getkey. While this can seem
surprising at first, a real keyboard controller is responsible for
repeats and modifier actions depend on the state of the keyboard which
is only tracked in real-time.
In this commit, getkey() has not changed yet apart from indirectly using
the keydev interface with pollevent(). It will be changed soon to use
event transforms in keydev_read(), and will be left in charge of
providing repeat profiles, handling return-to-menu, backlight changes
and timeouts, all of which are user convenience features.
* dnsize() works like dsize() but a limit on the number of bytes is
specified. This is useful to obtain the length of a substring.
* drsize() has a reverse limit; the input specifies a number of pixels
and the function determines how much of the input fits. This is useful
for word wrapping algorithms.
This parameter controls the maximum number of glyphs to print.
For backwards compatibility, it is automatically inserted by a macro in
older calls with only 7 parameters.
This function performs a more rigorous analysis of the mapped region by
checking continuity. So far all pages mapped in userpsace have been
contiguous, so the results are identical to gint[HWURAM].
Page size is now optionnaly provided in mmu_translate() and its
subfunctions; programs that use this function need to add a second NULL
parameter.
* Create an `src/3rdparty` folder for third-party code (to add the
Grisu2B alfogithm soon).
* Split the formatted printer into gint's kprint (src/kprint), its
extension and interface (include/gint/kprint.h), and its use in the
standard stdio functions (src/std/print.c).
* Slightly improve the interface of kformat_geometry() to avoid relying
on knowing format specifiers.
* Add a function to register more formatters, to allow floating-point
formatters without requiring them.
The repeat delays of getkey() are adjusted automatically, however a
repeat that is currently going on might be affected.
Also, repeat delays are always approximated as a whole number of
keyboard scans so an increase in scan frequency can impact the speed at
which repeats are emitted.
This change moves the gint version declaration from a symbol in a
compile-time generated object file to a preprocessed header installed in
the library tree.
This makes it possible to determine the gint version statically from the
headers, which is much more robust in complex build systems that use
version information such as CMake's find_package().
This change adds a new TMU function timer_spinwait() which waits for a
timer to raise its UNF flag. This makes it possible to wait even when
interrupts are disabled.
This is used by the new CPG function sleep_us_spin() which waits for a
given delay without using interrupts. This is currently used in SPU
initialization.
This commit introduces custom character spacing with a new fxconv
parameter "char-spacing". Word spacing is also tied to the width of the
space character (0x20). This removes the need for special semantics on
the space character, but requires that its size be specified with gray
pixels for proportional fonts.
This also fixes problems with the size of spaces in dsize() not being
correlated with their size during rendering, since on fx-9860G topti
already used the glyph's with as word spacing.
Since fxconv changes but gint's Makefile does not track updates to
external tools, a full rebuild of gint is required past this commit.
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.
This change introduces a new getkey_repeat_filter() function that can be
used to individually accept, deny or delay repeat events for specific
keys and timings.
This new mechanism allows an add-in to be restarted after exiting by
just never exiting in the first place, calling gint_osmenu() instead.
This makes sure that we can relaunch the add-in immediately, which is
normally possible through an option in the OS though no OS-independent
method of setting it is currently known.
Because this is gint_osmenu(), known pitfalls apply. On all platforms,
it is necessary to prepare the first frame before leaving. On fx-CG 50,
the inevitable display border is also there.
Disables spread spectrum by default so that the frequency estimations of
the CPG driver (notably used by the timer driver and libprof) are more
accurate.
This change modifies the font_t type to replace the concept of charset
with a more generic list of non-overlapping Unicode blocks defined by a
starting code point and a size.
It also takes advantage of the assembly feature of fxconv, introduced
for libimg long after the first version of topti, to support pointers in
the converted structure rather than having to tediously compute offsets
within a variable-size structure.
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.
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.
* 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 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 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!
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.
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]
The return code -1 noted in the BFile_FindFirst or BFile_FindNext is
from test, which mean it could be possibles that they are negative
error code from functions failing and not meaning that no file have been
found, to be sure, the value IML_FILEERR_ENUMERATEEND from filebios.h in
the fxlib need to be checked (and maybe defined in gint with a more
meaningful name for user interactivity)
This macro used to protect the declaration of the [vram] variable of
gint. This variable was short to keep drawing functions short but could
clutter the namespace.
That being said, it's even better to just [#define vram gint_vram] if
you need. This change renames the variable to [gint_vram], exposes it
whenever <gint/display.h> is included, and removes the GINT_NEED_VRAM
macro altogether.
This change adds a keydown() function that is synchronized with events,
ie. it returns the key state as seen by previously read events.
It also completely eliminates low-level repeat events, which are not
very meaningul as the keyboard scan frequency goes up (and would be
meaningless if KEYSC interrupts were used), and adapts getkey() by
giving it access to the current driver time through pollevent().
This change adds support for three sections .ilram, .xram and .yram,
along with three macros GILRAM, GXRAM and GYRAM, that can be used to
statically load data to on-chip memory.
The IL memory is unavailable when the processor goes to sleep, causing
any involved DMA transfer to stall. The dma_transfer_wait() normally
sleeps to save battery power, but this causes the whole system to freeze
and never wake up.
This change lets dma_transfer_wait() decide dynamically whether to sleep
or spinlock. There is no concrete improvement over dma_transfer_noint()
when using IL memory, but it makes dma_transfer() fully generic.
Obviously the same goes for X and Y memory.
Currently there seems to be no DMA at all on fx9860g. Further
investigation would be required, because this would be the first major
difference between the SH7305's found in fx9860g and fxcg50 models.
An automated peripheral register discovery strategy might help, but
identifying discovered registers would be non trivial.
Also use the pruning ability of the Makefile to avoid troublesome
ifdef's in the code.
This change introduces two new mechanismes for executing user code when
an exception occurs.
* This first is the custom panic message, which usually displays "System
ERROR". The function that performs this task can now be user-defined.
It is also run in user mode because the exception handler rte's into
it, allowing it to execute any kind of interrupt-inducing task. The
behavior is undefined if this function raises an exception.
* The second is an exception-catching function, which (when set) is
called every time an exception occurs, and is granted the chance of
handling the exception to continue execution normally. It can be used
in various ways, the most primitive of which is recording the
exception and going back. It runs in interrupt mode and must not raise
any kind of exception.
Behave like Basic's Horizontal and Vertical commands. Internal dline()
optimizations are renamed gint_dhline() and gint_dvline().
Also supports ghline() and gvline() in the gray engine.
Optimization cases here are amost negligible due to limiting RAM access
frequencies and the very limited amount of work accomplished in the
functions. Code maintainability is prioritized by using dline().
This change introduces exception handlers that default to a fatal error
with an on-screen description of the exception and some debugging
information.
It also adds the dprint() function as a definitely-needed helper and
removes bootlog_unmapped() by using the exception handler for the fatal
error display. (Also printf() is now required in all gint add-ins; this
is sad, but space is not as much of a constraint as debugging.)
Finally, the exception handler is used to handle an interrupt which is
an exception in practice, the DMA address error. On fx-CG 50, additional
DMA-related information is displayed on the screen. This is left out on
fx-9860G as there is not enough space.
This commit introduces bopti for fxcg50 with the first basic 16-bit
formats. The performance is rather slow, especially for large images,
and will need refinements and/or overclock to be really efficient in
full-screen real-time applications.
This commit introduces bopti for fx-CG 50. Currently the only
interfaces are the bopti_render_{clip,noclip} functions, and the
only supported formats are r5g6b5 and r5g6b5a.
The algorithm for r5g6b5 is optimized to perform longword accesses
using movua.l, whereas the algorithm for r5g6b5a uses plain word
accesses because transparency checks feel more difficult than one
more loop iteration.
These algorithms are still slow for large surfaces and struggle to
keep up 25 FPS in full-screen, so possible improvements with the
DMA should definitely be tested before restorting to overclock.
This change finally introduces gray image rendering with bopti. This
is the final iteration of bopti v2 and certainly the fastest so far.
All four profiles are supported, without change to the format.
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.
This makes it possible to write application code without specifying the
target machine, which is especially useful for libraries. The first user
of this system is libprof.
Since Memallox's newlib port is currently unstable, gint has to
provide some standard functions on its own. Instead of a single
<gint/std.h> header, this commit makes a gint/std directory containing
headers under standard names.
* Now uses topti instead of fxlib for text (including MMU failure)
* Fit .pretext into 4k for everything before MMU succeeds
* A short version of sprintf() for dynamic messages
* Support a driver function, status(), to allow early driver debug
* Expose more useful platform information in <gint/mpu.h>
* Expose the first of a few CASIOWIN syscalls