Complete Technical Reference

Fantasy Pi Console

Full ISA, System Trap, and C++ SDK reference for the Fantasy Pi virtual console platform.

ISA Instruction Set Architecture

The Fantasy Pi VM is a 32-bit RISC processor with 16 general-purpose registers, 32 fixed-length instructions, and 4 condition flags.

Instruction Format

Every instruction is exactly 32 bits wide and follows this layout:

OP
6b
COND
4b
DST
4b
SRCA
4b
SRCB
4b
IMM10
10b

OP = opcode (6 bits)  |  COND = condition code (4 bits)  |  DST = destination register (4 bits)  |  SRCA/SRCB = source registers (4 bits each)  |  IMM10 = 10-bit signed immediate (10 bits)

For load and jump instructions the lower 22 bits form a signed 22-bit immediate (IMM22).

Condition Codes

The upper 4 bits of every instruction are a condition predicate. The instruction only executes if the predicate is true.

CodeMnemonicMeaningFlag Test
0x0alAlwaystrue
0x1eqEqual / ZeroZ set
0x2neNot equalZ clear
0x3gtSigned greater thanZ clear && N clear
0x4ltSigned less thanN set
0x5geSigned greater or equalN clear
0x6leSigned less or equalZ set || N set
0x7csCarry setC set
0x8ccCarry clearC clear
0x9miMinus / negativeN set
0xAplPlus / positive or zeroN clear
0xBvsOverflow setV set
0xCvcOverflow clearV clear

ALU & Data-Processing Opcodes

OpcodeMnemonicOperationFlagsDescription
0x00nopNo operation. Advances PC by 4.
0x01loaddst = simm22Load 22-bit signed immediate into destination register.
0x02movdst = srcACopy value from source to destination.
0x03adddst = srcA + srcBZ N C V32-bit unsigned addition with full flag update.
0x04subdst = srcA - srcBZ N C V32-bit subtraction. Sets flags for signed/unsigned comparisons.
0x05muldst = srcA * srcBZ N C V32-bit multiply. Lower 32 bits of the 64-bit result are written.
0x06divdst = srcA / srcBUnsigned division. Division by zero returns 0.
0x07moddst = srcA % srcBUnsigned modulo. Modulo by zero returns 0.
0x08anddst = srcA & srcBZ NBitwise AND.
0x09ordst = srcA | srcBZ NBitwise OR.
0x0Axordst = srcA ^ srcBZ NBitwise XOR.
0x0Bnotdst = ~srcAZ NBitwise NOT (complement).
0x0Cshldst = srcA << (srcB & 31)Z N CLogical shift left. Shift amount is masked to 5 bits.
0x0Dshrdst = srcA >> (srcB & 31)Z N CLogical shift right (zero-fill).
0x0Esardst = (int32_t)srcA >> (srcB & 31)Z N CArithmetic shift right (sign-extend).
0x0FcmpsrcA - srcBZ N C VCompare. Updates flags but does not write a result.

Memory Opcodes

OpcodeMnemonicOperationDescription
0x10lddst = mem32[srcA + simm10]Load 32-bit word from RAM or ROM mirror. Reads little-endian.
0x11stmem32[srcA + simm10] = srcBStore 32-bit word to RAM only. Writes little-endian.
0x12ldbdst = mem8[srcA + simm10]Load unsigned byte from RAM or ROM mirror.
0x13stbmem8[srcA + simm10] = srcBStore byte to RAM only.
0x14ldhdst = mem16[srcA + simm10]Load unsigned halfword (16-bit) from RAM or ROM mirror.
0x15sthmem16[srcA + simm10] = srcBStore halfword to RAM only.
0x16pushsp -= 4; mem32[sp] = dstPush a 32-bit register onto the stack.
0x17popdst = mem32[sp]; sp += 4Pop a 32-bit value from the stack into a register.

Control Flow Opcodes

OpcodeMnemonicOperationDescription
0x18jmppc = (pc & 0xFFC00000) | imm22Unconditional jump. Target is 22-bit absolute within the current 4 MB region.
0x19jeqif Z: pc = targetJump if equal (zero flag set).
0x1Ajneif !Z: pc = targetJump if not equal.
0x1Bjgtif !Z && !N: pc = targetJump if signed greater than.
0x1Cjltif N: pc = targetJump if signed less than.
0x1Dcalllr = pc; pc = targetCall subroutine. Return address stored in LR (R14).
0x1Eretpc = lrReturn from subroutine.
0x1Ftraptrap(imm10)System trap. See Trap Reference for all vectors.

Flag Bits

Z — Zero

Set when the result of an ALU operation is zero.

N — Negative

Set when bit 31 of the result is 1 (signed negative).

C — Carry

Set on unsigned overflow (carry out of bit 31) or borrow on subtraction.

V — Overflow

Set on signed overflow (result sign differs from operands).

Assembly Example

; Set up stack and call main
.global _start
_start:
    load    sp, #0x000FFFFC       ; STACK_TOP
    call    main_init

; Simple loop: sum 0..99 in r0
sum_loop:
    load    r0, #0              ; accumulator
    load    r1, #1              ; step
    load    r2, #100            ; limit
.loop:
    add     r0, r1
    cmp     r0, r2
    jlt     .loop
    ret

SYS System Trap Reference

Traps are system calls invoked with the trap instruction. The trap vector (0–1023) is passed in the lower 10 bits of the instruction. Registers R0–R15 are used for arguments and return values according to the calling convention below.

Calling convention — Arguments are placed in R0, R1, R2 … in order. Return values are written back into R0 (and R1 if two words are returned). The VM always handles HALT (0x00) internally; all other traps are dispatched to the kernel trap handler.

Graphics Traps (0x10 – 0x18)

VectorNameArgs (Regs)ReturnsDescription
0x10GFX_INITR0=w, R1=hInitialize framebuffer. Defaults to 640×480 if args are 0.
0x11GFX_PRESENTRequest frame presentation. VM pauses until next frame.
0x12GFX_CLEARR0=colorFill back buffer with 32-bit ARGB color.
0x13GFX_DRAW_SPRITER0=spriteId, R1=x, R2=y, R3=blendModeDraw a registered sprite at (x,y) using the given blend mode.
0x14GFX_DRAW_IMAGER0=surfId, R1=x, R2=y, R3=blendModeDraw a raw surface (image) at (x,y).
0x15GFX_BITBLTR0=srcId, R1=dstX, R2=dstY, R3=srcX, R4=srcY, R5=w, R6=h, R7=mode, R8=globalAlphaBlit a rectangle from source surface to framebuffer.
0x16GFX_DRAW_TILEMAPR0=mapId, R1=scrollX, R2=scrollYRender a registered tilemap with pixel scrolling.
0x17GFX_SET_PALETTER0=palId, R1=idx, R2=colorWrite one color into a palette. palId 0–15, idx 0–255.
0x18GFX_DRAW_TEXTR0=fontId, R1=strAddr, R2=(y<<16)|x, R3=colorDraw a null-terminated string from RAM. Address is relative to RAM base.

Blend Modes

ValueNameDescription
0CopyOpaque copy, no blending.
1AlphaStandard alpha blend (premultiplied source over destination).
2ColorKeyCopy pixels that do not match the transparent color key.
3AdditiveAdd source RGB to destination RGB, clamp to 255.

Audio Traps (0x20 – 0x22)

VectorNameArgsDescription
0x20AUDIO_INITReset the software audio mixer.
0x21AUDIO_PLAYR0=sampleId, R1=channel, R2=volumePlay a sample on the given channel (0–7). Volume 0–255.
0x22AUDIO_STOPR0=channelStop playback on the given channel.

Input Traps (0x30 – 0x32)

VectorNameArgsReturnsDescription
0x30INPUT_POLLRefresh the input state buffer in RAM at 0x00010000.
0x31INPUT_KEYR0=keycodeR0=0/1Query a single key (0–255). Returns 1 if pressed, else 0.
0x32INPUT_GAMEPADR0=playerR0=buttons, R1=LX, R2=LYRead gamepad state for player 0 or 1. Buttons are a 32-bit bitmask.

Input State Layout (RAM 0x00010000)

struct InputState {
    uint32_t keyboard_keys[8];      // 256 key bits
    uint32_t gamepad_buttons[2];  // 2 players
    int16_t  gamepad_axis[2][4];  // LX, LY, RX, RY
    uint32_t mouse_x;
    uint32_t mouse_y;
    uint32_t mouse_buttons;
};

Memory Traps (0x40 – 0x41)

VectorNameArgsDescription
0x40MEM_COPYR0=src, R1=dst, R2=lenCopy len bytes from src to dst within RAM. Uses memmove semantics (overlaps safe).
0x41MEM_FILLR0=dst, R1=value, R2=lenFill len bytes starting at dst with value & 0xFF.

Math Traps (0x50 – 0x52)

VectorNameArgsReturnsDescription
0x50MATH_RANDR0=seed (optional)R0=nextLinear congruential generator. If seed != 0, re-seeds the generator.
0x51MATH_SINR0=angleR0=fixed16.16Sine of angle (0–65535 maps to 0–2π). Returns 16.16 fixed-point.
0x52MATH_COSR0=angleR0=fixed16.16Cosine of angle (0–65535 maps to 0–2π). Returns 16.16 fixed-point.

Debug Traps (0x60 – 0x61)

VectorNameArgsDescription
0x60DEBUG_LOGR0=valuePrint R0 as unsigned decimal to the debug console / serial.
0x61DEBUG_LOG_STRR0=addrPrint a null-terminated string from RAM to the debug console.

Core Traps

VectorNameArgsDescription
0x00HALTStop the VM. The program ends. Handled internally by the VM.
0x01SLEEPR0=millisecondsDelay execution for the given number of milliseconds.

Trap Usage Example

; Clear screen to black and draw a sprite
    load    r0, #0xFF000000       ; black (ARGB)
    trap    0x12               ; GFX_CLEAR

    load    r0, #0              ; sprite ID
    load    r1, #100            ; x
    load    r2, #200            ; y
    load    r3, #1              ; Alpha blend mode
    trap    0x13               ; GFX_DRAW_SPRITE

    trap    0x11               ; GFX_PRESENT

MEM Memory Map & Registers

Memory Layout

RegionStartEndSizePurpose
RAM0x000000000x00FFFFFF16 MBGeneral-purpose memory, stack, variables, heap.
VRAM0x010000000x017FFFFF8 MBVideo memory: framebuffers, sprite sheets, tile data.
ROM0x020000000x03FFFFFF32 MBCartridge ROM mapped for read-only access via ld.

Register File

The VM exposes 16 general-purpose 32-bit registers (R0–R15). Several registers have dedicated roles in the ABI:

RegisterNameRole
R0 – R12General purpose. Arguments and return values start in R0.
R13SPStack pointer. Initialized to 0x000FFFFC on reset.
R14LRLink register. Holds return address for call.
R15PCProgram counter. Reads as current + 4.

Hardware Limits

Memory

16 MB RAM, 8 MB VRAM, 32 MB ROM maximum.

Display

640×480 default framebuffer. Up to 1920×1080 supported.

Sprites

256 max sprites. Max size 256×256 per sprite.

Tiles

1024 max tiles. 16 tilesets. 16 palettes × 256 colors.

Audio

8 PCM channels, 16-bit stereo, 44100 Hz.

Performance

~1 million VM cycles per frame at 60 FPS.

CPP C++ SDK Reference

The C++ runtime abstracts the virtual hardware through a thin header-only layer. You write game logic against these headers; the IDE generates asset IDs, scene IDs, GameObject type IDs, and named GameObject instance IDs automatically.

Engine Lifecycle

#include <fantasy_engine.h>

int main() {
    fe::Engine_Init();               // Set up subsystems
    fe::Engine_LoadScene(SCENE_FOREST_01);

    while (true) {
        fe::Engine_PollInput();      // Update input state
        fe::Engine_Update();         // Run all GO_Update callbacks
        fe::Engine_Draw();           // Draw tilemaps + GO_Draw callbacks
    }
    return 0;
}

Graphics API

FunctionParametersDescription
fe::Engine_Init()Initialize the engine and all subsystems.
fe::Engine_LoadScene(id)uint32_t sceneIdSwitch to a generated scene ID such as SCENE_FOREST_01, reset object handles, and spawn scene/map instances.
fe::Engine_CurrentScene()Return the currently loaded scene ID, or SCENE_NONE.
fe::Scene_Load(id)uint32_t sceneIdAlias for Engine_LoadScene.
fe::Scene_Current()Alias for Engine_CurrentScene.
fe::Engine_PollInput()Read hardware input and write to RAM input state.
fe::Engine_Update()Call all registered GameObject Update callbacks.
fe::Engine_Draw()Render tilemaps and call all Draw callbacks.
fe::Engine_PlaySFX(id, ch)uint32_t sampleId, uint8_t channelPlay a sound effect on the given channel.
fe::Gfx_Clear(color)uint32_t argbClear the back buffer.
fe::Gfx_Present()Flip buffers and wait for vsync.

Sprite & Tilemap API

FunctionParametersDescription
fe::Sprite_Draw(id, x, y, flip)uint32_t id, int x, int y, uint8_t flipDraw a sprite with optional horizontal/vertical flip.
fe::Sprite_DrawEx(id, x, y, mode, alpha)+ BlendMode mode, uint8_t alphaDraw with blend mode and global alpha override.
fe::Tilemap_DrawLayer(id, scrollX, scrollY)uint32_t layerId, int sx, int syRender a tilemap layer with pixel scrolling.
fe::Palette_SetColor(pal, idx, color)uint8_t pal, uint8_t idx, uint32_t argbUpdate a single palette entry at runtime.

Input API

FunctionParametersReturnsDescription
fe::Input_IsPressed(btn)uint32_t buttonboolTrue if button was pressed this frame (edge).
fe::Input_IsHeld(btn)uint32_t buttonboolTrue if button is currently held down.
fe::Input_IsReleased(btn)uint32_t buttonboolTrue if button was released this frame (edge).
fe::Input_GamepadAxis(player, axis)uint8_t p, uint8_t aint16_tRead analog axis value (LX=0, LY=1, RX=2, RY=3).

Button Constants

BUTTON_UP

D-pad up

BUTTON_DOWN

D-pad down

BUTTON_LEFT

D-pad left

BUTTON_RIGHT

D-pad right

BUTTON_A

Primary action

BUTTON_B

Secondary action

BUTTON_START

Pause / menu

BUTTON_SELECT

Select / back

Audio API

FunctionParametersDescription
fe::Audio_Init()Reset the mixer and clear all channels.
fe::Audio_Play(sample, ch, vol)uint32_t id, uint8_t ch, uint8_t volStart playback. Volume 0–255.
fe::Audio_Stop(ch)uint8_t chStop a channel immediately.
fe::Audio_SetVolume(ch, vol)uint8_t ch, uint8_t volChange volume of an active channel.

GameObject API

GameObjects are the primary gameplay entities. The IDE generates type IDs and a registration table from the GameObject Editor. You only implement the callback functions.

Type / FunctionSignatureCalled
GameObjectstruct { uint16_t type_id; uint16_t instance_id; Vec2 pos; Vec2 vel; Rect collider; uint32_t sprite_id; uint32_t anim_id; uint32_t state; uint32_t flags; void* user_data; }Entity instance structure.
GO_InitFuncvoid (*)(GameObject* self)Once when the object is spawned.
GO_UpdateFuncvoid (*)(GameObject* self)Every frame before drawing.
GO_DrawFuncvoid (*)(GameObject* self)Every frame after tilemap render.
GO_CollisionFuncvoid (*)(GameObject* self, GameObject* other)When two colliders intersect.
GO_InteractFuncvoid (*)(GameObject* self, GameObject* other)On player-trigger interaction.
fe::GO_GetInstance(id)GameObject* (uint32_t instanceId)Return a named scene/map instance in the currently loaded scene, or nullptr.

Named Map Instances

When you paint on an Object layer in the Studio Map editor, the selected tile is stored as map data and a real GameObjectInstance is attached to that map. Select the painted object and set its Instance-Name in the right-side settings panel. During code generation the IDE writes generated/gameobject_instances.h with one GOINST_* constant per named instance.

// Object layer instance name in the Map editor: player
#include <fantasy_engine.h>

void Door_Update(GameObject* self) {
    GameObject* player = fe::GO_GetInstance(GOINST_PLAYER);
    if (player) {
        Vec2 p = fe::GO_GetPos(player);
        if (p.x > 120) {
            fe::GO_SetPos(self, 200, self->pos.y);
        }
    }
}
Instance lookup is scene-local. GO_GetInstance(GOINST_PLAYER) returns a valid pointer only while the scene containing that named map object is loaded. After Engine_LoadScene, reacquire the pointer instead of caching it across scenes.

GameObject Registration Macro

// In a .cpp file — the IDE generates the registry automatically
#include "generated/gameobject_types.h"

struct EnemyData { int hp; int patrolDir; };

void EnemySlime_Init(GameObject* self) {
    auto* d = static_cast<EnemyData*>(self->user_data);
    d->hp = 3;
    d->patrolDir = 1;
    self->sprite_id = ASSET_SPR_ENEMY_SLIME;
    self->collider = { 0, 0, 16, 16 };
}

void EnemySlime_Update(GameObject* self) {
    auto* d = static_cast<EnemyData*>(self->user_data);
    self->pos.x += d->patrolDir;
    if (self->pos.x > 200 || self->pos.x < 50)
        d->patrolDir = -d->patrolDir;
}

void EnemySlime_OnCollision(GameObject* self, GameObject* other) {
    if (other->type_id == GOID_PLAYER) {
        fe::Engine_PlaySFX(ASSET_SFX_HIT, 0);
    }
}

Math & Utility

FunctionParametersReturnsDescription
fe::fp_mul(a, b)int32_t a, int32_t bint32_t16.16 fixed-point multiply. Result is 16.16.
fe::fp_div(a, b)int32_t a, int32_t bint32_t16.16 fixed-point divide. Result is 16.16.
fe::fp_from_int(i)int32_t iint32_tConvert integer to 16.16 fixed-point.
fe::fp_to_int(f)int32_t fint32_tConvert 16.16 fixed-point to integer (truncates).
fe::Math_Rand(seed)uint32_t seeduint32_tPseudo-random number. Seed 0 returns next value.
fe::Math_Sin(angle)uint32_t angleint32_tSine in 16.16 fixed-point. Angle 0–65535 = 0–2π.
fe::Math_Cos(angle)uint32_t angleint32_tCosine in 16.16 fixed-point.
Fixed-Point Format — 16.16 means 16 integer bits (including sign) and 16 fractional bits. The value 1.0 is represented as 0x00010000. Use fe::fp_mul and fe::fp_div instead of raw * and / to keep the scale correct.

Complete Project Structure

my_game/
src/
main.cpp // Engine_Init + main loop
player.cpp // GOID_PLAYER callbacks
enemy.cpp // GOID_ENEMY callbacks
generated/ // Auto-generated by IDE
asset_ids.h // #define ASSET_SPR_PLAYER 0
gameobject_types.h // #define GOID_PLAYER 0
gameobject_registry.cpp // Type table
map_forest_01_data.cpp // Static tile arrays
engine_config.h // Hardware limits as #defines
assets/
sprites/player.png
tilesets/ground.png
maps/forest_01.json
game.fproj