| name | troubleshoot-amiberry |
| description | Use when investigating, reproducing, or fixing Amiberry bugs, especially renderer or input regressions, HiDPI or SDL3 logical-presentation bugs, Vulkan capability or swapchain failures, crash regressions, or behavior regressions. Follow an edit-build-run-test-fix cycle, using Amiberry MCP runtime-control tools when they are configured and falling back to normal process, log, screenshot, and debugger tools otherwise. |
Amiberry Autonomous Troubleshooting
Debug and fix Amiberry bugs through iterative edit-build-run-test-fix cycles with minimal user interaction.
Environment
Amiberry source is at the current working directory (or a nearby amiberry/ directory).
If the Amiberry MCP server (amiberry-mcp-server) is configured, use it for runtime control and observation. If it is not available, fall back to normal process launch, logs, screenshots, and debugger tools.
Determine the platform before building:
- macOS: Build natively with
cmake
- Linux / WSL2: Build with
cmake (use wsl -e prefix if on Windows host)
- Windows (native): Build with llvm-mingw (clang + lld) via CMake presets and Ninja
Build Commands
Linux / macOS
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DUSE_IPC_SOCKET=ON
cmake --build build --parallel
Windows host targeting WSL2
wsl -e bash -c "cd ~/amiberry && cmake --build build --parallel"
Windows (native llvm-mingw)
# Use the helper script if present (sets PATH for cmake/ninja/llvm-mingw, VCPKG_ROOT, LLVM_MINGW_ROOT)
powershell -ExecutionPolicy Bypass -File "build_and_run.ps1"
# Or manually:
$env:LLVM_MINGW_ROOT = "C:\llvm-mingw"
$env:VCPKG_ROOT = "D:\Github\vcpkg"
cmake --preset windows-debug
cd out/build/windows-debug
ninja -j12
# Run with logging enabled
.\amiberry.exe --log
Windows build notes:
- Build dir:
out/build/windows-debug (or windows-release)
- Toolchain: llvm-mingw (clang + lld + libc++) via
cmake/Toolchain-x86_64-w64-mingw32.cmake. The MinGW-w64 / GCC build was retired; do not try to mix GCC and clang outputs.
LLVM_MINGW_ROOT must point at an extracted llvm-mingw release (or C:\llvm-mingw\bin must be on PATH)
- Kill stale
amiberry.exe before rebuild if "permission denied"
write_log() is silent unless --log flag or write_logfile config is set
- x86-64 JIT is supported on Windows; for high-natmem, pointer-width, or performance regressions use the
amiberry-x86-jit skill
- PowerShell
$env: variables get stripped in bash inline commands; use .ps1 files with -File
Troubleshooting Workflow
Phase 1: Understand the Bug
- Read the bug description / issue carefully
- Identify which subsystem is likely involved (graphics, input, audio, CPU emulation, chipset, config, GUI, etc.)
- Search the codebase for relevant code:
- Use
rg to find related functions, variables, error messages
- Use
rg --files to find relevant source files
- Read the code to understand the current behavior
- Form a hypothesis about the root cause
Phase 2: Reproduce
-
Launch Amiberry with appropriate config:
- Use
launch_and_wait_for_ipc to start Amiberry and wait for IPC readiness
- Specify a model (
A500, A1200, etc.) or config file as needed
- This automatically enables logging
-
Verify it's running:
- Use
health_check to confirm process + IPC + emulation status
-
Set up the reproduction scenario:
- Use
runtime_load_config to load specific configurations
- Use
runtime_insert_floppy to insert disk images
- Use
send_key to navigate menus or trigger actions
- Use
runtime_set_config to change specific options
-
Observe the behavior:
- Use
runtime_screenshot_view to see what's on screen
- Use
tail_log to monitor log output
- Use
runtime_get_fps to check performance
- Use
runtime_get_cpu_regs / runtime_get_custom_regs for hardware state
-
If it crashes:
- Use
get_crash_info to detect the crash and analyze signals + log patterns
- Use
get_process_info for exit code and signal details
Phase 2a: Split Shared Bugs Into Concrete Paths
Before editing, decide whether the bug is in a shared subsystem or only one renderer/input path.
- Treat these coordinate spaces as distinct:
- Window coordinates: raw SDL event coordinates
- Drawable pixel coordinates: OpenGL/Vulkan backbuffer size
- Render/logical coordinates: SDL renderer logical presentation space
- For SDL renderer logical-presentation bugs, pass raw window coordinates to SDL conversion helpers such as
SDL_RenderCoordinatesFromWindow() or SDL_ConvertEventToRenderCoordinates(). Do not pre-scale and then ask SDL to scale again.
- Check mouse, pen, and tablet paths together. If only
SDL_EVENT_MOUSE_MOTION is fixed, stylus/tablet input often remains offset.
- Separate renderer-specific behavior before changing code:
- SDL renderer path:
SDL_Renderer, logical presentation, viewport, pen/mouse conversion
- OpenGL path: drawable size, external shaders, texture filtering, OSD path
- Vulkan path: instance/device/swapchain capability probing, no SDL renderer fallback assumptions
- When debugging visual regressions, verify the exact path that owns the blur or scaling issue. OSD textures, main frame textures, and external shader input textures are different paths and should not be "fixed" together by assumption.
Phase 3: Fix
- Make code changes using
apply_patch on the Amiberry source files
- Keep changes minimal - fix only what's broken, don't refactor surrounding code
- Kill the running instance: Use
kill_amiberry
- Rebuild:
cmake --build build --parallel
- Check build output for errors. If build fails, fix and retry.
Phase 4: Verify
-
Restart with same config: Use restart_amiberry or launch_and_wait_for_ipc
-
Run the same reproduction steps from Phase 2
-
Check results:
runtime_screenshot_view - does the screen look correct?
tail_log - are there still errors/warnings?
get_crash_info - did it crash again?
health_check - is everything still running?
-
If NOT fixed: Go back to Phase 3 with new hypothesis
-
If fixed: Clean up and report findings
Phase 4a: Renderer And Capability Verification
- For HiDPI issues, test both SDL renderer and OpenGL/Vulkan paths when relevant. A fix in one path does not prove the others are correct.
- For Vulkan startup failures, gate everything against reported capabilities:
- composite alpha from
supportedCompositeAlpha
- image usage bits such as
TRANSFER_DST_BIT
- present modes and surface formats
- Prefer "probe, then enable" over hardcoding spec-preferred flags.
- If the bug involves presentation or scaling, verify both startup and post-resize behavior.
Phase 5: Report
Summarize:
- What the bug was (root cause)
- What was changed (files and line numbers)
- How to verify the fix
- Any side effects or concerns
Amiberry MCP Tools Reference
Use these tools when the Amiberry MCP server is available in the current session.
Process Lifecycle
| Tool | Purpose |
|---|
check_process_alive | Is Amiberry running? Returns PID + exit code |
get_process_info | Detailed info: PID, status, signal, crash detection |
kill_amiberry | Force kill (SIGTERM then SIGKILL) |
wait_for_exit | Block until process exits (with timeout) |
restart_amiberry | Kill + relaunch with same command |
Workflow
| Tool | Purpose |
|---|
launch_and_wait_for_ipc | Launch with logging, wait for IPC ready |
health_check | Combined: process + IPC ping + status + FPS |
Observation
| Tool | Purpose |
|---|
runtime_screenshot_view | Screenshot returned as image data |
tail_log | New log lines since last read |
wait_for_log_pattern | Wait for regex in log (with timeout) |
get_crash_info | Process signals + log crash pattern scanning |
Emulation Control
| Tool | Purpose |
|---|
pause_emulation / resume_emulation | Pause/resume |
reset_emulation | Soft or hard reset |
frame_advance | Step N frames when paused |
runtime_set_config / runtime_get_config | Change/query config at runtime |
runtime_load_config | Load a .uae config file |
Debugging
| Tool | Purpose |
|---|
runtime_get_cpu_regs | All CPU registers (D0-D7, A0-A7, PC, SR) |
runtime_get_custom_regs | Custom chip registers (DMACON, INTENA, etc.) |
runtime_read_memory | Read Amiga memory (1/2/4 bytes) |
runtime_write_memory | Write Amiga memory |
runtime_disassemble | Disassemble at address |
runtime_set_breakpoint / runtime_clear_breakpoint | Breakpoints |
runtime_debug_activate / runtime_debug_step | Debugger control |
runtime_debug_step_over | Step over JSR/BSR |
runtime_get_copper_state / runtime_get_blitter_state | Hardware state |
Media & Display
| Tool | Purpose |
|---|
runtime_insert_floppy / runtime_eject_floppy | Floppy management |
runtime_insert_cd / runtime_eject_cd | CD management |
send_key | Send keyboard input (Amiga keycodes) |
runtime_set_display_mode | Window/fullscreen/fullwindow |
runtime_set_ntsc | PAL/NTSC switching |
Amiga Keycodes (common)
| Key | Code | Key | Code |
|---|
| Return | 0x44 | Space | 0x40 |
| Escape | 0x45 | Backspace | 0x41 |
| Up | 0x4C | Down | 0x4D |
| Left | 0x4F | Right | 0x4E |
| F1-F10 | 0x50-0x59 | Help | 0x5F |
| Left Amiga | 0x66 | Right Amiga | 0x67 |
| A-Z | 0x20,0x35,0x33,0x22,0x12,0x23,0x24,0x25,0x17,0x26,0x27,0x28,0x37,0x36,0x18,0x19,0x10,0x13,0x21,0x14,0x16,0x34,0x11,0x32,0x15,0x31 | | |
To send a keypress, call send_key twice: once with state=1 (press), then state=0 (release).
Key Source Directories
| Directory | Contents |
|---|
src/ | Core emulation (UAE-derived) |
src/osdep/ | Platform abstraction (Linux/macOS/Android/Windows) |
src/osdep/imgui/ | GUI panels (Dear ImGui) |
src/include/ | Headers and interfaces |
src/osdep/amiberry_ipc_socket.cpp | IPC socket implementation |
src/osdep/amiberry_gfx.cpp | Graphics/display |
src/osdep/amiberry_input.cpp | Input handling |
src/osdep/amiberry.cpp | Core platform layer |
src/osdep/macos_bookmarks.h/.mm | macOS security-scoped bookmarks (App Store) |
macOS Path Notes
- macOS user data now defaults to
~/Documents/Amiberry; startup migration handles legacy ~/Library/Application Support/Amiberry.
- When constructing shell commands with paths, always quote arguments.
download_file() properly quotes paths in curl/wget commands via popen().
create_missing_amiberry_folders() uses std::filesystem::copy() instead of system("cp -R ...").
- The app bundle at
build/Amiberry.app stores resources (controllers, data, roms, whdboot) under Resources/.
Tips
- Always use
--log (handled automatically by launch_and_wait_for_ipc) for log output
- Use
tail_log frequently to catch errors early
- If the screen looks wrong,
pause_emulation + runtime_screenshot_view gives a stable frame
- If a fix touches input coordinates, explicitly note which coordinate space each variable is in
- If a fix touches rendering quality, verify OSD, main frame, and external shader paths independently
- For timing-sensitive bugs, use
runtime_set_config to change CPU speed or floppy speed
- For crashes, the signal name in
get_crash_info tells you a lot: SIGSEGV = null pointer/bad memory, SIGABRT = assertion/abort, SIGBUS = alignment
- Build with Debug type (
-DCMAKE_BUILD_TYPE=Debug) for better crash info
- If you need to test multiple configs, use
kill_amiberry + launch_and_wait_for_ipc between each
ARM64 JIT testing
- ARM64 JIT stability checks should be validated with at least 3 configs: SysInfo, A4000, and Lightwave.
Input & On-Screen Joystick Troubleshooting
-
On-screen D-pad acts like a mouse instead of joystick: Two possible causes:
- SDL touch-to-mouse synthesis: SDL3 can synthesize
SDL_EVENT_MOUSE_BUTTON_* / SDL_EVENT_MOUSE_MOTION from touch events. Fix: filter event.button.which == SDL_TOUCH_MOUSEID / event.motion.which == SDL_TOUCH_MOUSEID in mouse event handlers when on-screen joystick or the on-screen keyboard is active. Pen/stylus paths also use SDL_PEN_MOUSEID filtering in amiberry_input.cpp.
- Wrong port assignment: Another device (e.g., Android accelerometer) may be assigned to Port 1, overriding the on-screen joystick. The on-screen joystick auto-assigns to Port 1 via
on_screen_joystick_set_enabled(true), but check changed_prefs.jports[1].id to verify.
-
On-screen joystick not appearing in Input dropdown: The virtual device is only registered when currprefs.onscreen_joystick is enabled. Check this preference first. Then verify registration in init_joystick() (input_platform_internal_host.h): num_joystick < MAX_INPUT_DEVICES and osj_device_index is set. The device appears as "On-Screen Joystick" in the joystick device list.
-
Input injection debugging: Use --log flag. The on-screen joystick logs "On-Screen Joystick registered as JOY%d" at startup. Use setjoystickstate()/setjoybuttonstate() (proper device API); avoid send_input_event() which bypasses port mode configuration.
-
Port mode mismatch: If port 1 mode is not JSEM_MODE_JOYSTICK, D-pad input may behave as mouse. The auto-assignment sets changed_prefs.jports[1].mode = JSEM_MODE_JOYSTICK and calls inputdevice_config_change().
Windows-Specific Troubleshooting
- Black screen with USE_OPENGL: Usually caused by JIT
jit_abort() → uae_reset() permanently setting quit_program, which blocks pixel drawing in waitqueue(). Fixed in src/jit/x86/compemu_x86.h.
- GUI crash only with debugger: Debug builds (
-DDEBUG) enable assert() in tinyxml2. This can cause crashes with debugger attached but not in normal execution. Not a real bug.
- Symlink failures in WHDBooter: Windows requires admin or Developer Mode for symlinks. Directory symlinks use
std::filesystem::copy() directly. File symlinks have try-catch fallback.
- Winsock differences:
close() → closesocket(), ioctl() → ioctlsocket(), errno → WSAGetLastError(). Check src/slirp/ for patterns.
- No log output:
write_log() returns early if neither --log nor write_logfile is enabled. Always pass --log when debugging.
- GUI crash on startup (missing data dir): If the
data/ directory (fonts, icons) is missing from the runtime working directory, ImGui's AddFontFromFileTTF asserts and crashes in debug builds (exit code 3). Fix: main_window.cpp checks std::filesystem::exists(font_path) before loading. Deployment fix: copy data/ from source tree to working directory.
- Config save does nothing: WinUAE-style
"ccs=UTF-8" modes and POSIX 'e' close-on-exec modes are not portable across Amiberry's Windows path. Use plain "w"/"rt"/"wt" modes under #ifdef AMIBERRY in cfgfile.cpp/ini.cpp, and use uae_fopen() for paths that need 'e' stripped on Windows.
- Hardfile RDB not detected in GUI: ImGui
hd.cpp was missing hardfile_testrdb() call after HDF file selection, causing geometry to stay at 32,1,2 instead of auto-detecting RDB (0,0,0). Fixed in commit c2b5c053.