Troubleshooting & Limits
This guide covers advanced topics that you might encounter as your projects grow in complexity. Here, you’ll find solutions to common limitations and techniques to push what’s possible on the Classpad. As new techniques are discovered, they will be added here, so be sure to check it regularly. If you encounter some issue that isn’t yet known or listed here, feel free to 💬 Join our Discord community or report it as issue in our GitHub bug tracker.
Overcoming the 64kb App Size Limit
Section titled “Overcoming the 64kb App Size Limit”As your application grows, you might run into a strict 64 kilobyte (kb) size limit for your compiled ELF binary that prevent it loading properly. This is a fundamental constraint of the standard memory space allocated for applications.
Issue description
Section titled “Issue description”When your application’s compiled code exceeds 64kb, the calculator’s loader cannot place it in the default memory region. This typically results in your app crashing or freezing immediately upon launch, without any clear error message. The standard memory space allocated for an app is simply not large enough for bigger projects.
Solution: Using VBAK Memory
Section titled “Solution: Using VBAK Memory”To bypass the 64kb limit, you can instruct the linker to place your application’s code in a larger memory area known as vbak or vram. These regions, normally used for system operations like video memory backup, each offer approximately 330kb of space.
To do this, you need to add a specific linker flag to your project’s Makefile.
- Open your
Makefile. - Locate the
LD_FLAGSvariable. - Add the following flag:
-Wl,-Ttext-segment,0x8C052800
Your LD_FLAGS line should look something like this:
LD_FLAGS = -Wl,-Ttext-segment,0x8C052800This flag tells the YAL (HH3/v3) loader to place the executable code segment at the memory address 0x8C052800, which corresponds to the vbak area.
Important Side Effect: Managing the Screen Buffer
Section titled “Important Side Effect: Managing the Screen Buffer”Placing your application code in the vbak region comes with a critical responsibility: you must now manually restore the screen’s contents restore after run. Because your code occupies the memory space the operating system would use to back up the screen (vram), you must save and restore the screen state yourself upon starting and exiting your app.
Doing it is hopefully trivial, you need to override the default calcInit and calcExit functions. The following code allocates a temporary buffer on the heap, copies the current screen content into it, and restores it when the app closes.
#include <type_traits>#include <sdk/os/file.h>#include <sdk/os/debug.h>#include <sdk/os/lcd.h>#include <sdk/os/string.h>#include <sdk/calc/calc.h>#include <cstring>#include <cstdlib>
// A backup pointer for the original vram contentstd::remove_pointer_t<decltype(vram)> (*vram_bak)[width * height];
// This function is called when your app startsvoid calcInit(void){ // Allocate memory on the heap to store the screen backup vram_bak = (decltype(vram_bak))malloc(sizeof(*vram_bak));
// If allocation fails, we can't proceed safely if (!vram_bak) { return; }
// Copy the current screen content to our backup buffer memcpy(vram_bak, vram, sizeof(*vram_bak)); // Clear the screen for the app memset(vram, 0, sizeof(*vram_bak));}
// This function is called when your app exitsvoid calcExit(void){ // Copy the backed-up screen content back to vram memcpy(vram, vram_bak, sizeof(*vram_bak)); // Refresh the LCD to show the restored content LCD_Refresh(); // Free the memory we allocated for the backup free(vram_bak);}For a complete implementation of this technique, you can look at the source code for CPDoom. The project uses the vbak memory region and provides a clear example of overriding calcInit and calcExit in its bootstrap.cpp file.
Address Error
Section titled “Address Error”A common cause of crash is linked to a message simmilar to the following:
ADDRESS(R) ERROR!TARGET=BDF7BE03PC=8CFF3B48Here’s common causes of crash to investigate :
Address (w) error
Section titled “Address (w) error”This mean the program tried to write at an address that’s not valid or not allowed. Check the target value. Here’s a concrete example and its fix:
ADDRESS(W) ERROR!TARGET=8CFFF275PC=8007D452From the CPapp.elf.map (generated at compile time) that target is in .bss.event (0x8cfff275) in that case, the error indicate “address write error”.
The crash location 0x8007D452 (0x80XXXXXX = ROM) looks close to the GetInput (0x8007CE2C) call (use the addresses mapping from the sdk with your rom version to determine them).
If the crash is in GetInput or related to it, and the target is .bss.event, the event variable is likely in .bss (uninitialized data).
If GetInput writes to &event, and event is at 0x8cfff275, but 0x8cfff275 is an odd address (ends in 5, so not 4-byte aligned), GetInput expects an aligned pointer, and event is unaligned, writing to it might cause an exception.
In that case, the fix is to eother align event, or reorder variables to ensure alignment: Change uint8_t to uint32_t or add alignas(4).
address (r) error
Section titled “address (r) error”The easiest solution is to run sh4aeb-elf-addr2line -ipfe dist/CPapp.elf 8CFF3B48 (change with your elf file and target/pc address)
It would output something similar to :
_ZN8Renderer12draw_MinimapEb at /workspaces/CP-3D-CarGoWroom/src/Renderer.cpp:303 that give you hint on where the issue is.
Sometimes the line isn’t available, and you’d need to troubleshoot the cause of the issue by looking at the CPapp.elf.map file that’s generated at compile time.
Here’s another alignment issue:
ADDRESS(R) ERROR!TARGET=8CF791FFPC=8005A578The PC is close the file methods : { "FunctionName": "File_FindFirst", "startAddress": "0x8005A2AC" ... }, in that case File_FindFirst crash at 0x8CF791FF (unaligned address) is due to misaligned pointers passed to it (g_wpath, fileName, or findInfoBuf).
The fix was to align globals in src/internal.hpp and locals in src/commands/ls.cpp to 4 bytes using __attribute__((aligned(4))) to prevent unaligned access crash in File_FindFirst.