* Create a heap arena over the OS stack, large enough to hold two VRAMs
as was previously done, unless GINT_NO_OS_STACK is set at compile
time. (This replaces GINT_USER_VRAM.)
* Allocate a single VRAM in the heap at startup.
* Use double buffering by default as triple buffering is almost entirely
useless. dudpate() waits if both VRAMs are identical to prevent
corruption, but this can be bypassed with R61524 functions as usual.
This adds about 180 kB of heap data to any add-in using default
settings.
* Stop trying to be smart and generate repeats on the fly; this breaks
time consistency. Also if repeats are not handled in time this causes
infinite loops.
* Move rarely-used functions to external files, simplify stuff, get rid
of internal driver events; saves ~1 kB per add-in overall.
This helped locate some bugs:
* read() could read past EOF due to BFile_Read() allowing you to read up
until the end of the last sector, beyond the file size
* pread() did not restore the file offset because the negative seek at
the end is not relative (that was the CASIOWIN fs API), so pread()
could not actually be written without knowing the current position
* lseek() would clamp you to EOF but still return its out-of-bounds
arguments, as a direct result of BFile_Seek() doing that
Benefits:
* Made pread() a generic function
This changes fixes the way gint uses the FIFO controllers D0F and D1F
to access the FIFO. It previously used D0F in the main thread and D1F
during interrupt handling, but this is incorrect for several reasons,
mainly the possible change of controllers between a write and a commit,
and numerous instances of two FIFOs managing the same pipe caused by
the constant switching.
gint now treats FIFO controllers as resources allocated to pipes for
the duration of a commit-terminated sequence of writes. The same
controller is used for a single pipe in both normal and interrupt
modes, and released when the pipe is committed. If no controller is
available, asynchronous writes fail and synchronous ones wait.
The fxlink API is also added with a small amount of functions, namely
to transfer screenshots and raw text. Currently these are synchronous
and do not use the DMA, this will be improved later.
Finally:
* Removed pipe logic from src/usb/setup.c, instead letting pipes.c
handle the special case of the DCP (which might be regularized later)
* Removed the usb_pipe_mode_{read,write} functions as they're actually
about FIFo controllers and it's not clear yet how a pipe with both
read and write should be handled. This is left for the future.
* Clarified end-of-sequence semantics after a successful commit.
This change introduces new sleep_block() and sleep_unblock() functions
that control whether the sleep() function actually sleeps. This type of
behavior was already implemented in the DMA driver, since DMA access to
on-chip memory is paused when sleeping (on-chip memory being paused
itself), which would make waiting for a DMA transfer a freeze.
Because DMA transfers are now asynchronous, and USB transfers that may
involve on-chip memory are coming, this API change allows the DMA and
USB drivers to block the sleep() function so that user code can sleep()
for interrupts without having to worry about asynchronous tasks
requiring on-chip memory to complete.
This change introduces the global "feature function" that can be
enabled in getkey() to receive events, and use them for
application-wide features. This would be useful, for instance, to
toggle screen backlight with a different key combination that the
default, to capture screenshots, or to implement a catalog.
When enabled, the feature function is present with all new events and
can perform actions, then decide whether or not to return them from
getkey().
* Properly define the callback time of a write/commit as the time when
the pipe is available again for further writing.
* Refuse commits when writes are pending; instead, enforce a strict
order of finishing writes before committing, which makes sense since
consecutive writes are ordered this way already.
* Properly support callbacks for writes and for commits.
* Define the synchronous APIs in terms of waiting until the callbacks
for equivalent asynchronous functions are invoked (plus initial
waiting for pipes to be ready).
This change adds asynchronous capabilities to the DMA API. Previously,
transfers would start asynchronously but could only be completed by a
call to dma_transfer_wait(). The API now supports a callback, as well
as the dma_transfer_sync() variant, to be consistent with the upcoming
USB API that has both _sync and _async versions of functions.
The interrupt handler of the DMA was changed to include a return to
userland, which is required to perform the callback.
* dma_transfer() is now an obsolete synonym for dma_transfer_async()
with no callback.
* dma_transfer_noint() is now a synonym for dma_transfer_atomic(), for
consistency with the upcoming USB API.