Wonderful Toolchain project update - November 2025

Published on November 30, 2025

Here’s what I’ve been tinkering with for the past two months with the Wonderful toolchain.

WonderSwan improvements

The main focus of my work in autumn was improving the wswan and wwitch targets. Let’s give the changes a closer look.

AthenaOS

For the longest time, one of my personal issues with the state of Wonderful was that testing and sharing homebrew for the official WonderSwan hobbyist development kit - Qute Corporation’s WonderWitch - was, ironically, less attractive than creating native cartridge images. There are a few reasons for that:

  • Worse compiler support for the DS != SS memory configuration that it relies on. I’d like to tackle this in the future if interest grows as bug reports arrive.
  • Worse development pipeline - fewer emulators support the WonderWitch, while XMODEM transfer is less convenient than make && emulate.
  • Legal issues - unlike testing and playing native cartridge images, WonderWitch homebrew relies on FreyaBIOS, an abstraction layer and font library, as well as FreyaOS, which provides file system and process functionality. These binaries are proprietary, so I cannot redistribute or modify them. The BIOS component in particular is not officially available online.

Let’s try to tackle the latter two issues by looking at the past for a moment.

When the IBM PC was released in 1981, it used off-the-shelf components, coupled with a proprietary BIOS. The only company which could add features or otherwise improve this BIOS was IBM. Without the BIOS, programs made for the IBM PC did not work correctly. History showed that all it took was someone stubborn enough to create a clean room re-implementation of the BIOS; in the PC’s case, it began with Columbia Data Systems and, later, Compaq.

If you have known me for a while, you are probably aware that I can be very stubborn. Since 2023, I have taken steps to do exactly this - document, test and write a new implementation of the Witch’s BIOS and OS based on the resulting findings, all without examining the binaries themselves. The end result of this work is called AthenaOS.

AthenaBIOS is, currently, an almost complete reimplementation of FreyaBIOS’s API. In addition to being open source, it allows porting the abstraction layer to platforms with distinct memory layouts or storage flashing routines.

AthenaOS is, currently, a work in progress reimplementation of FreyaOS’s libraries. It has support for .il intermediate libraries, partial handling of the /rom0 and /ram0 file systems, as well as stubs of some other parts of libraries12.

Both components eventually achieved a very high degree of compatibility with the existing software library, giving me confidence in their usability. As such, they enabled me to add a new command to the toolchain: wf-wwitchtool mkrom, and integrate it with the build system:

$ make
  MKROM   example.ws
info: /rom0 file count is 1
info: adding example.fx
info: executable #0, headers at DFE4:0000, files at DFE8:0000
writing example.ws
info: placing example.fx at DFE8:0000

The mkrom command allows turning any .fx executable, plus any number of auxilliary data files, into a .ws ROM file that can be used in any emulator or environment with at least 1283 kilobytes of SRAM, bound only by terms of the MIT license. It may even be possible to re-release your old games for the platform in this way - I’ve been thinking of writing an HTML5 emulator for the system for this purpose, so please let me know if you’re interested!

PS. To be clear, this is not the first time someone has achieved this - trap15’s romwitch provided the same functionality. However, that implementation relied on cartridge data from the game Judgement Silversword: Rebirth or Dicing Knight., which came with a special version of the official OS intended for this purpose.

libwse

Next, let’s discuss some initial steps towards better development ergonomics.

The wswan target, up until recently, featured two main libraries:

  • libws, a low-level set of hardware definitions and helpers,
  • libwsx, a collection of assorted but unconnected routines useful for developing programs (BCD, decompression, unpacking).

To further support this pair of libraries, I’ve long wanted to add a third one, libwse. It would provide more opinionated wrapper functionalities on top of libws, operating at a higher level of abstraction. The ultimate goal here is to provide features closer to toolchains/libraries like SGDK or ZGB - making common operations for game engines easier, but which impose a certain structure on your code as a result. This, then, would lower the learning curve required to make games with the toolchain!

As I’m not sure how to go about these features yet, for the time being, the only purpose of libwse is making memory allocation easier. Gone are the days of being required to write an iram.h file and mess about with __attribute((section(".iram_2000.tiles"))) extern const uint8_t tiles[]; - now you can do this:

#include <wse/memory.h>

// Reserve memory for 256 2BPP and 256 4BPP tiles.
WSE_RESERVE_TILES(256, 256);
// Now you can use WS_TILE_MEM(15) to reference the memory for tile 15!

// ...
// Clear the first two screens.
ws_screen_fill_tiles(&wse_screen1, 0, 0, 0, WS_SCREEN_WIDTH_TILES, WS_SCREEN_HEIGHT_TILES);
ws_screen_fill_tiles(&wse_screen2, 0, 0, 0, WS_SCREEN_WIDTH_TILES, WS_SCREEN_HEIGHT_TILES);

In essence, <wse/memory.h> provides default symbols and macros which will be placed in the correct memory regions by wf-wswantool build, simplifying the barrier to entry for writing games on the engine. An example adaptation for joe’s WonderCell can be seen here.

Remaining changes

There have also been many smaller changes across the tooling. They are listed below:

  • crt0: Added support for GCC constructor/destructor attributes.
  • examples: Added example of using <wsx/console.h>.
  • libc: Added strtok().
  • libc: Fixed strcasecmp().
  • libc: Updated nanoprintf, reducing the binary size of code using sprintf() and similar functions.
  • libws: Added ws_bank_*_get helpers.
  • libws: Added ws_bank_with_flash helper.
  • libws: Improved Karnak I/O port definitions.
  • target: Added assembly helper IA16_CALL_LOCAL, which emits faster calls between functions in the same segment on medium targets.
  • target: Wrote documentation for <ia16.h>.
  • wf-mednafen: Fixed out of bounds memory access for SRAM.
  • wf-mednafen: Improved interrupt emulation in wf-mednafen.
  • wf-tools: Added support for reading and extracting .fx files to wf-mkfent.
  • wf-tools; Fixed wf-mkfent --mode.
  • wf-tools: Fixed support for the __bank symbol prefix.
  • wf-tools: Optimized wf-wswantool build’s internal linker.
  • wf-tools: Removed the previous method of building WonderWitch programs as ROMs, libwwcl. It was much more effortful to implement, requiring manual porting, than the new method.

Other improvements

While this cycle mostly featured improvements for the ‘Swan, some features meant for ARM targets also made the cut:

  • toolchain-gcc-arm-none-eabi: ARMv6-M multilibs are now bundled.
  • toolchain-gcc-arm-none-eabi: Updated binutils, FreeType and libpng16.
  • wf-fatfs: Updated to R0.16p1.
  • wf-tools: Added color output to wf-*tool usage.
  • wf-tools: Added --symbol-top to wf-*tool usage, with C++ demangling support.
  • wf-tools: Added wf-config clean-caches to remove unused cache files.

Closing thoughts

I’ve seen Lunoka start work on a port of Mai Nurse using Wonderful. That was pretty cool to see!

As always, thank you for following Wonderful! Please let me know what you think of the updates, and consider making something with the tools! If you’re feeling like something is stopping you from trying them out, such as documentation, or if you just like something that I’m doing, feel free to provide feedback - we’re all more than happy to answer questions, and hearing back from people can be a great motivator.


  1. It also features a stub implementation of the BMPSaver library, which is required to run at least one famous WonderWitch game due to a bug in the publicly distributed version, and was only available on an FTP server for registered WonderWitch owners. ↩︎

  2. Notably, it is missing support for file streams and process management, but I have not managed to identify any existing program actually taking advantage of these features yet! ↩︎

  3. With the --small argument passed, as this will technically disable some of the system’s multi-process functionality in the future. ↩︎