In this chapter, you're going to learn the basics of compiling and testing a homebrew project targetting the WonderSwan.
First, set up a new project:
$ mkdir first-program/ # (1)! $ wf-wswantool project new first-program/ # (2)!
Next, compile it:
$ cd first-program/ $ make
The build script will output lines similar to the following:
CC src/main.c LD build/first-program_stage1.elf ROM first-program.wsc MERGE compile_commands.json
src/main.c.build/first-program_stage1.elf is being linked. This file will contain all of the program's source code and assets, but not yet placed in the console's ROM and RAM.first-program.wsc is being created, now with the correct memory placements.compile_commands.json file is being generated. This is used by your IDE to provide syntax highlighting; as a consequence, it is a good idea to run `make` after adding a new .c file to the project.Finally, you can run the ROM file using your emulator of choice.
The program is not displaying anything - after all, there's no code written yet!
Let's examine the src/main.c file:
// SPDX-License-Identifier: CC0-1.0
//
// SPDX-FileContributor: Adrian "asie" Siekierka, 2023
// (1)!
#include <wonderful.h> // (2)!
#include <ws.h> // (3)!
void main(void) {
while(1);
}
wonderful.h include contains common CPU/target definitions. It's a good idea to put it in essentially every C file.ws.h include contains hardware definitions specific to the WonderSwan, as well as many lower-level hardware abstraction functions.Pay special attention to the `while(1);` at the end - this is an infinite loop.
You may be used to ending `main()` with a `return;` of some type. On bare metal, however, one should not return from main, as there's no operating system to return to. Removing it will cause the system to jump to arbitrary code, with unforeseen consequences!
With only an infinite loop in main, it's clear that the code won't do anything. Let's make it do something!
For now, we're going to assume a “mono” program - we'll introduce the color mode in a later chapter. On the “mono” WonderSwan, the palette pipeline that converts tile information to display shades consists of two parts: the palette, mapping each of the four possible palette indexes to one of eight color values; and a shade look-up table, mapping each of the color values to one of the sixteen total shades which the panel can display.
First, we need to initialize the shade look-up table. At the beginning of main, add the following function call:
ws_display_set_shade_lut(WS_DISPLAY_SHADE_LUT_DEFAULT);
This sets a default shade look-up table, with the color value 0 corresponding to the brightest shade (0) and 7 to the darkest shade (15).
As the “mono” WonderSwan's panel is a monochrome LCD, it's shades with lower values which are brighter. The opposite is true for the WonderSwan Color's RGB values.
Next, we need to enable the display. We're going to enable the “screen 1” layer - as the WonderSwan's memory is zeroed by default, this should not cause anything to be drawn to the screen, but will enable viewing the background color - which, by default, is the first of eight color values:
outportw(WS_DISPLAY_CTRL_PORT, WS_DISPLAY_CTRL_SCR1_ENABLE);
Finally, we're going to do some changes to the display. Edit the while(1) loop as follows to cycle the first palette:
while (1) {
outportw(WS_SCR_PAL_0_PORT, inportw(WS_SCR_PAL_0_PORT) + 1); // (1)!
ws_delay_ms(1000); // (2)!
}
That's all! Compile the code using make and run it in your emulator of choice. If done correctly, you should see the display slowly change colors from brightest to darkest and back again.