Skip to content

Migrating to V3

Migrating your Classpad HHK (v2) project to HH3 (v3) require a few tweaks to your codebase.

Update configuration files to reflect the new SDK requirements:

  • Makefile: Adjust compiler flags and target settings.
  • CI Configurations: Update build pipelines to use the new toolchain.
  • Devcontainer: Modify container setup to include V3 dependencies.
  • clangd: Regenerate compile_commands.json and restart clangd for proper IDE support.
  • .gitignore: Update to include new build artifacts:
    *.bin
    *.elf
    *.hh3
    *.map
    # temporary files under WSL
    *~
    .*~

The linker.ld file can be safely removed as the SDK now handles linking automatically.

Replace your old Makefile with the new structure:

Before:

APP_NAME:=tetris
ifndef SDK_DIR
$(error You need to define the SDK_DIR environment variable, and point it to the sdk/ folder)
endif
AS:=sh4-elf-as
AS_FLAGS:=
CC:=sh4-elf-gcc
CC_FLAGS:=-ffreestanding -fshort-wchar -Wall -Wextra -O2 -I $(SDK_DIR)/include/
CXX:=sh4-elf-g++
CXX_FLAGS:=-ffreestanding -fno-exceptions -fno-rtti -fshort-wchar -Wall -Wextra -O2 -I $(SDK_DIR)/include/
LD:=sh4-elf-ld
LD_FLAGS:=-nostdlib --no-undefined
READELF:=sh4-elf-readelf
OBJCOPY:=sh4-elf-objcopy
AS_SOURCES:=$(wildcard *.s)
CC_SOURCES:=$(wildcard *.c)
CXX_SOURCES:=$(wildcard *.cpp)
OBJECTS:=$(AS_SOURCES:.s=.o) $(CC_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
APP_ELF:=$(APP_NAME).hhk
all: $(APP_ELF) Makefile
clean:
rm -f $(OBJECTS) $(APP_ELF)
$(APP_ELF): $(OBJECTS) $(SDK_DIR)/sdk.o linker.ld
$(LD) -T linker.ld -o $@ $(LD_FLAGS) $(OBJECTS) $(SDK_DIR)/sdk.o
$(OBJCOPY) --set-section-flags .hollyhock_name=contents,strings,readonly $(APP_ELF) $(APP_ELF)
$(OBJCOPY) --set-section-flags .hollyhock_description=contents,strings,readonly $(APP_ELF) $(APP_ELF)
$(OBJCOPY) --set-section-flags .hollyhock_author=contents,strings,readonly $(APP_ELF) $(APP_ELF)
$(OBJCOPY) --set-section-flags .hollyhock_version=contents,strings,readonly $(APP_ELF) $(APP_ELF)

After:

APP_NAME:=tetris
ifndef SDK_DIR
$(error You need to define the SDK_DIR environment variable, and point it to the sdk/ folder)
endif
AS:=sh4a_nofpueb-elf-gcc
AS_FLAGS:=
FUNCTION_FLAGS=-flto -ffat-lto-objects -ffunction-sections -fdata-sections -O2 -gdwarf-5
CC:=sh4a_nofpueb-elf-gcc
CC_FLAGS:=$(FUNCTION_FLAGS) -Wall -Wextra -I $(SDK_DIR)/include/
CXX:=sh4a_nofpueb-elf-g++
CXX_FLAGS:=$(FUNCTION_FLAGS) -Wall -Wextra -I $(SDK_DIR)/include/
LD:=sh4a_nofpueb-elf-g++
LD_FLAGS:=$(FUNCTION_FLAGS) -Wl,--gc-sections -L$(SDK_DIR)
READELF:=sh4a_nofpueb-elf-readelf
OBJCOPY:=sh4a_nofpueb-elf-objcopy
STRIP:=sh4a_nofpueb-elf-strip
AS_SOURCES:=$(wildcard *.S)
CC_SOURCES:=$(wildcard *.c)
CXX_SOURCES:=$(wildcard *.cpp)
OBJECTS:=$(AS_SOURCES:.S=.o) $(CC_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
APP_ELF:=$(APP_NAME).elf
APP_OUT:=$(APP_NAME).hh3
elf: $(APP_ELF) Makefile
hh3: $(APP_OUT) Makefile
all: $(APP_ELF) $(APP_OUT) Makefile
.DEFAULT_GOAL := all
clean:
rm -f $(OBJECTS) $(APP_ELF) $(APP_ELF).map $(APP_OUT)
$(APP_ELF): $(OBJECTS) $(SDK_DIR)/libsdk.a
$(LD) -Wl,-Map $@.map -o $@ $(LD_FLAGS) $(OBJECTS) -lsdk
$(APP_OUT): $(APP_ELF)
$(STRIP) -o $@ $^

Rename header extensions from .hpp to .h, except for GUI-related headers.

Before:

#include <appdef.hpp>
#include <sdk/os/debug.hpp>
#include <sdk/os/input.hpp>
#include <sdk/os/lcd.hpp>
#include <sdk/os/mem.hpp>

After:

#include <appdef.h>
#include <sdk/os/debug.h>
#include <sdk/os/input.h>
#include <sdk/os/lcd.h>
#include <sdk/os/mem.h>

Update deprecated syntax patterns:

  • char *num = "0000"char num[] = "0000"
  • for (int x = ...for (auto x = ...
  • Use static_cast<type>(value) instead of C-style casts
  • Use proper types: int32_tint, etc.

Change the main function:

Before:

extern "C" void main() {
// code
}

After:

int main() {
// code
return 0;
}

Or for full environment access:

int main(int argc, char **argv, char **envp) {
// code
return 0;
}
  • Remove LCD_VRAMBackup() and LCD_VRAMRestore()
  • Remove calcInit() and calcEnd() calls
  • Remove global VRAM declarations like uint16_t *vram;

Replace old memory functions:

  • memsetMem_Memset
  • And other similar memory operations

Ensure your main file contains proper app metadata:

APP_NAME("Your App Demo")
APP_DESCRIPTION("Displays a demo on the ClassPad.")
APP_AUTHOR("your_name")
APP_VERSION("1.0.0")

Rename structures to match new conventions:

  • InputEventInput_Event
  • InputScancodeInput_Scancode

Take advantage of V3 improvements:

  • Use __builtin_unreachable(); for unreachable code paths
  • Add return 0; at the end of main function
  • Initialize LFSR directly: uint16_t lfsr = 0x453A;

Check if calcInit and calcEnd are still needed. In most cases, they are no longer required and can be removed.

Take advantage of the new support for libc and libstdc++ by refactoring code to use standard library functions where appropriate.

Consider embedding binary assets directly into the ELF file instead of loading them separately to simplify deployment.

Review and fix any new warnings or errors reported by the updated compiler.

If your app loads into VRAM:

  • You no longer need a special launcher.
  • Load directly into vbak.
  • Override calcInit and calcEnd (they are weak by default) to implement custom VRAM backup logic and avoid overwriting your own data.
  • Paths: Paths are const char_const16_t* (UTF-16).
  • Strings: Use char16_t arrays and u"path" literals. Cast to (const char_const16_t*) when calling SDK functions.
  • Alignment: File path buffers passed to SDK functions (like File_FindFirst) MUST be 4-byte aligned on SuperH. Use __attribute__((aligned(4))).
  • Structs: File_FindInfo uses scoped enums like File_FindInfo::EntryTypeDirectory (or just EntryTypeDirectory depending on SDK version/macros). Check scoping.
  • Polling: Use GetInput instead of GetKey.
  • Struct: struct Input_Event MUST be 4-byte aligned. Use __attribute__((aligned(4))). Misalignment causes crashes (address error) at runtime.
  • Keycodes: Use KEYCODE_* enums.
  • Touch: Coordinates in Input_Event are int32_t. Cast to uint32_t if comparing with unsigned bounds to avoid compiler warnings.
  • PEG (System) UI is currently not working.
  • Input_GetKeyState is not functional in this version.

Before:

#include <appdef.hpp>
#include <sdk/os/debug.hpp>
extern "C" void main() {
Debug_PrintString("Hello World");
}

After:

#include <appdef.h>
#include <sdk/os/debug.h>
APP_NAME("Hello World App")
APP_DESCRIPTION("Displays Hello World")
APP_AUTHOR("Developer")
APP_VERSION("1.0.0")
int main() {
DebugPrintString("Hello World");
return 0;
}
  • Crashes: If it crashes in an SDK function (e.g., GetInput, File_Find...), check ALIGNMENT of the structs/buffers passed to it.
  • Linker Errors: “Multiple definition of …” usually means a conflict with SDK symbols (e.g., fillScreen). Rename your function or wrap in #ifdef PC.
  • Compile Errors: “Did you mean…?” implies the symbol exists but maybe signature mismatch or missing namespace. Check SDK headers.
  • Warnings: Suppress warn_unused_result by checking return value if (func() < 0) {} rather than (void)func().