Skip to content

Stable branch Changelog

Giovanni Bajo edited this page Feb 22, 2023 · 17 revisions

Changelog of the stable branch.

This pages lists all main features that have been merge to the stable branch (trunk), and is updated quarterly. If you want to see the upcoming features, have a look at the unstable branch which is where features are developed and stabilized.

2023 Q1

Support for usage of fatfs

Years ago, libdragon started linking with fatfs, and this prevented software (such as flashcart menus) to bring their own copies of fatfs because of duplicated symbols failure. Now libdragon exports fatfs.h, so basically applications can rely on fatfs directly if they need to. Remember that for SD card access, you can use the libdragon debug library, without needing to use fatfs directly.

The change also allowed files on the SD card to be generated using the correct time whenever a RTC is present. Simply call rtc_init() to initialize the RTC, and then create a file via fopen("sd:/test.txt", "wb"): you will see it with the correct timestamp.

Binary toolchain built via CI

Historically, libdragon has provided a script to build a toolchain on a Linux system, but the user had to build the toolchain on their own computer. The only alternative for a long time was the usage of a Docker container. Now, libdragon builds via CI an updated toolchain that is uploaded on GitHub, for Windows and Linux (deb/rpm).

Please make sure to follow the installation instructions.

FPU Exceptions activated by default

Libdragon now activates MIPS FPU exceptions by default. This allows the game to instantly crash whenever there is a division by zero, or uninitialized memory is accessed by the floating point unit, which in turns helps catching bugs much earlier and with fewer surprises. When the exception screen triggers, it shows the PC address where the exception triggered, that you can lookup in the map file to see the name of the function.

2022 Q4

Speedup boot

We improved the libdragon boot by using PI DMA instead of CPU writes to load the binary from ROM, and also avoiding loading some part that was preloaded by IPL3. The boot was speedup by about 200ms for a standard ROM.

C++ exceptions

You can now reliably use C++ exceptions in libdragon games, they used to be unsupported before. Uncaught exceptions terminate the program and display an error message on the debug channel (on the unstable branch, they are properly caught and displayed in the upcoming inspector).

Support for arbitrary screen resolutions

Libdragon now supports configuring arbitrary resolution via display_init. Before, the choice was limited to a few common ones like (320x240, 640x480, etc.), but the VI hardware has a flexible resolution scaler so it is actually able to configure any resolution between 2 and 800 horizontal, and between 2 and 600 vertical. Assuming a proper 3D engine that adapts the viewport to the current resolution, increasing resolution to some custom value (until FPS is high enough) is a good way to increase the visual quality of a game.

This is an example configure a custom 444x240 resolution:

    display_init((resolution_t){ .width=444, .height=240, .interlaced=false }, DEPTH_16_BPP, GAMMA_NONE, ANTIALIAS_RESAMPLE);

Improved syntax for RSP assembly

RSP assembly syntax has been improved. It is now possible to reduce the number of arguments avoiding redundant ones, like in the following example where all lines produce the same instruction:

    vaddc $v01, $v01, $v02,e(0)
    vaddc $v01, $v01, $v02
    vaddc $v01, $v02,e(0)
    vaddc $v01, $v02

Moreover, a new dot-based syntax has been added to element specifiers that is easier to write and read, more similar to GLSL shaders, and also more orthogonal in its usage across the different opcodes:

    vaddc $v01, $v02.e4      # Add the contents of lane 4 of $v02 to all lanes in $v01
    vmov  $v01.e7, $v02.e1   # Move lane 1 of $v02 into lane 7 of $v01.

Expert users will notice that the syntax .eN always uniformly refers to a lane, even though it is ended differently in different opcodes. The equivalent version in SGI syntax for vmov would be:

    vaddc $v01, $v02[e4]
    vmov  $v01[e15], $v02[e9]   # !!!

In addition to .eN to specify a lane, there is also .qN and .hN for partial broadcasts in math opcodes.

2022 Q3

Add APIs to handle the reset button and the pre-NMI interrupt

When the reset button is pressed, a pre-NMI interrupt is generated and a 500ms grace time is given before the console is reset (as the RCP must be in idle state before the NMI happens). It is now possible to register a handler for the pre-NMI interrupt via register_RESET_handler(). Moreover, for simpler use cases where it is sufficient to poll whether the reset button was pressed or not, it is possible to call exception_reset_time() that will return the number of ticks since the button was pressed (or 0 if it wasn't pressed).

Some initial support has also be added to help leaving the RCP in idle state. For instance, the audio library will stop sending buffers to AI just before the NMI arrives, and the mixer library will also fade out the audio automatically during the 500ms grace time.

New surface_t structure

Libdragon now defines surface_t which is an arbitrary rectangular surface, with a specific pixel format (tex_format_t).

This is a building block upon which the new rdpq library will build upon (in the unstable branch). display_lock() has been updated to return a surface_t* now, so that it's possible to easily access the pixels of the current framebuffer if needed. Also graphics.h (the CPU-based drawing API) has been updated to draw upon a generic surface_t*, so that it can be used also on off-screen memory buffers.

Make dma_read_async / dma_write_async APIs work on the full PI range

Historically, both dma_read and dma_write constrain the provided PI addresses to the ROM address space, and this is impossible to change for backward compatibility.

The newer DMA APIs dma_read_async and dma_write_async (together with the raw counterparts: dma_read_raw_async and dma_write_raw_asycn) have been instead enhanced to work to the full address space, including for instance 64DD or SRAM.

2022 Q2

Support for CART interrupts

Devices on the cartridge connectors (eg: flashcarts, 64DD) can generate an interrupt called CART. It is now possible to register a handler for this interrupt via register_CART_handler() and enable it via set_CART_interrupt(true).

In fact, it is possible to register multiple interrupts as there will probably be more libraries that could wait for it (eg: a flashcard library and a 64DD library).

Misc new APIs

  • debug_hexdump() dumps a binary buffer to the debug channel, with a nice formatted hexdump format, including ASCII conversion.
  • malloc_uncached_aligned() allows to allocate an uncached memory buffer (just like malloc_uncached) but specifying an alignment for the base pointer.
  • rsp_write_begin() / rspq_write_arg() / rspq_write_end() allow to call a RSPQ function in an overlay with more than 16 arguments, which is the limit for the standard rspq_write() function. This is currently used in the unstable channel for the RDP triangle primitive that might require many different parameters.

Add workaround for AI hardware bug

A workaround has been added for the rare case of hitting a AI hardware bug that causes sound corruptions when the audio buffers happen to have some specific page alignment. The bug is also accurately reproduced on emulators such as Ares.

2022 Q2

Rework main exception handler including performance improvements

The main libdragon exception/interrupt handlers has been reworked with several improvements:

  • The exception frame is now saved to the standard user stack. Previously, a dedicated interrupt stack was used. In addition to saving memory for interrupt stack, this is a required step as we move towards a multi-threaded kernel, as each thread must have its own exception frame when preempted.
  • When servicing an interrupt, it is possible for an exception to trigger, reentrantly. This allows to better catch bugs in interrupt handlers (before, things like dereferencing a NULL pointer would go unnoticed as exceptions were disabled during interrupt servicing).
  • The state of the FPU is lazily saved for interrupt handlers, on the first actual usage of the FPU. Since most interrupt handlers do not need the FPU at all, the FPU state is not saved to the stack at all, improving speed.
Clone this wiki locally