struct dat { struct asd { u16 index; u16 icon_id; u16 mp_cost; u16 unknown; u16 targets; u8 name[32] | encoding('sjis') str; // The encoding actually depends on ROM region u8 description[256] | encoding('sjis') str; // ^ Ditto, we can't express this (we need parser options) u8 padding[726] nul; } ability[until (false)]; }; // # Instructions // // Instructions are variable-length with minimum size of 16 bits and maximum size of 128 bits[1]. // They are encoded with the following schema `5:name 2:n (16 * 2^n - 7):modifiers`, where `name` specifies the // instruction name and `n` specifies the total width of the instruction in bits with the formula `16 * 2^n`. // // Here's a table that shows how `n` maps to the instruction size: // n | instruction size in bits // 0 | 16 // 1 | 32 // 2 | 64 // 3 | 128 // // In the list below the notation for instruction and its modifiers is `NAME<1:arg1, 1:arg2> [STACK1] (STACK2)` // where `NAME` is the name of instruction, and inside the `<>` brackets are the modifiers for the instruction. // The optional number before the modifier tells the modifier size in bits, if omitted rest of the bits are used. // Inside `[]` brackets are the arguments that will be popped from the stack. `()` parenthesis are used instead, // if the stack argument is optional. // // Reserved registers: // r0: Always empty, used as NULL / empty data indicator // r1: Field counter // // List of instructions: // Name | Hex | Description // VERSION | 0x00 | Indicates the version of this bytecode. // REG | 0x01 | Allocates a new register. // * * If `len` is not zero, the next `len` bytes will be stored in this register. // PUSH | 0x02 | Pushes `v` to the stack. // PUSHR | 0x03 | Pushes the contents of register `r?` to the stack. // POP [v] | 0x04 | Pops `v` into register `r?`. // OP [...] | 0x05 | Performs operation specified by the `op`, and pushes the result to the stack. // QUEUE (...) | 0x06 | Queues next `len` bytes for execution for the next `IO` instruction. // * * The code is executed before or after `IO` instruction, depending whether VM is packing or unpacking. // IO [r?] (...) | 0x07 | Unpacking: Reads data from external VM input (usually a file) to register `r?`. // * * Packing: Writes data to external VM output (usually a file) from register `r?`. // * * `sz` is the size of the element in bits. // * * Rest of the stack is the number of elements, if empty, the elements to read/write is 1. // CALL (...) | 0x08 | Calls a function. The name of the function is stored in register `r?`. // JMP | 0x09 | Jumps to the `off` (in bytes). // JMPIF [v] | 0x0A | Performs `JMP`, if `v` is true. // // List of operations for the `OP` instruction: // Name | Hex | Argc | Description // UNM | 0x00 | 1 | Unary minus operation `-v1`. // LNOT | 0x01 | 1 | Logical not operation `!v1`. // BNOT | 0x02 | 1 | Bitwise not operation `~v1`. // MUL | 0x03 | 2 | Multiplication operation `v1 * v2`. // DIV | 0x04 | 2 | Division operation `v1 * v2`. // MOD | 0x05 | 2 | Modulo operation `v1 % v2`. // ADD | 0x06 | 2 | Addition operation `v1 + v2`. // SUB | 0x07 | 2 | Substraction operation `v1 - v2`. // SHIFTL | 0x08 | 2 | Left shift operation `v1 << v2`. // SHIFTR | 0x09 | 2 | Right shift operation `v1 >> v2`. // LESS | 0x0A | 2 | Less than operation `v1 < v2`. // LESSEQ | 0x0B | 2 | Less or equal operation `v1 <= v2`. // EQ | 0x0C | 2 | Equal operation `v1 == v2`. // NOTEQ | 0x0D | 2 | Not equal operation `v1 != v2`. // BAND | 0x0E | 2 | Bitwise and operation `v1 & v2`. // BOR | 0x0F | 2 | Bitwise or operation `v1 | v2`. // BXOR | 0x10 | 2 | Bitwise xor operation `v1 ^ v2`. // LAND | 0x11 | 2 | Logical and operation `v1 && v2`. // LOR | 0x12 | 2 | Logical or operation `v1 || v2`. // CTERNARY | 0x13 | 3 | Conditional ternary operation `v1 ? v2 : v3` // SUBSCRIPT | 0x14 | 2 | Subscript operation `v1[v2]` // // List of visuals: // Name | Hex | Representation // NUL | 0x00 | None // DEC | 0x01 | Decimal // HEX | 0x02 | Hexdecimal // STR | 0x03 | String // FLT | 0x04 | Float