|
1 |
| -# VM commands |
| 1 | +# AlphaDream VM documentation |
| 2 | + |
| 3 | +This is documentation for the specific VM used in Partners in Time. |
| 4 | +The VMs used in the rest of the M&L series are similar, but not identical. |
| 5 | + |
| 6 | +Huge thanks to the people at [BIS-docs](https://mnl-modding.github.io/BIS-docs/) for helping me figure this stuff out ❤️ |
| 7 | + |
| 8 | +# Command parsing |
| 9 | +Before parsing even begins, the VM has a table with command opcode attributes. |
| 10 | +It is not yet know exactly what these attributes look like, but they play a critical role in command parsing. |
| 11 | +The table is constant and never changes. |
| 12 | + |
| 13 | +Note in the following pseudo-code, `vm.read()` consumes 16 bits of data from the program. |
| 14 | +See [variable addressing modes](#variable-addressing-modes) for information on `vm.readVariables()`. |
| 15 | +[Command structs](#command-struct) are roughly read like this: |
| 16 | +```go |
| 17 | +// Read command metadata |
| 18 | +command.opcode = vm.read() |
| 19 | +attributes := vm.getAttributes(opcode) |
| 20 | +if attributes.hasResult { |
| 21 | + command.result = vm.read() |
| 22 | +} |
| 23 | +if attributes.hasFlags { |
| 24 | + command.flags = cm.read() |
| 25 | +} |
| 26 | + |
| 27 | +// Read arguments |
| 28 | +for i := 0; i < attributes.numArguments; i++ { |
| 29 | + if command.flags & (1 << i) == 0 { |
| 30 | + command.arguments[i] = vm.read() |
| 31 | + } else { |
| 32 | + command.arguments[i] = vm.readVariable(vm.read()); |
| 33 | + } |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +## Variable addressing modes |
| 38 | +When reading a VM variable, the top 4 bits of the variable are not used for the address, but for addressing mode. |
| 39 | +Here is a list of known addressing modes: |
| 40 | + |
| 41 | +### `0x0000`: 0 |
| 42 | +This addressing mode always returns 0. |
| 43 | + |
| 44 | +### `0x1000`: value from manager |
| 45 | +Reads a value from the script manager. |
| 46 | +Maybe from the stack? not sure... |
| 47 | +`return (u32*)(scriptManager)[1 + variable];` |
| 48 | + |
| 49 | +### `0x2000`: boolean flag |
| 50 | +Reads a single bit from a bitlist. |
| 51 | +Almost identical to `0xE000` + `0xF000`, but only has 12 bits for bit index. |
| 52 | +The bitlist read from is also not the same. |
| 53 | + |
| 54 | +### `0x3000`: field specific |
| 55 | +Calls to a function that is only valid when overlay 0 (field program) is loaded. |
| 56 | +If jumped to in battle, will probably crash the game completely. |
| 57 | +Unknown exactly what happens and what is returned. |
| 58 | + |
| 59 | +### `0x4000`: battle specific |
| 60 | +Same as `0x3000`, but for battles. |
| 61 | +Unknown what is returned from this method (more research needed). |
| 62 | + |
| 63 | +### `0x5000` through `0xD000`: TBD |
| 64 | +**More research needed!** |
| 65 | + |
| 66 | +## `0xE000` and `0xF000`: boolean flag |
| 67 | +Reads a single bit from a bitlist. |
| 68 | +The purpose of this bitlist is currently unknown. |
| 69 | +The value in the lower 13 (yes 13, not 12. That's why both E and F) is the bit index. |
| 70 | + |
| 71 | +## Data types |
| 72 | + |
| 73 | +### Command struct |
| 74 | +A command in the PiT VM looks like this: |
| 75 | +```C |
| 76 | +struct VmCommand { |
| 77 | + 0x00: u16, opcode // The command opcode |
| 78 | + 0x02: u16, result // The variable to store the result at |
| 79 | + 0x04: u16, flags // Determines if an argument is an immediate or not |
| 80 | + 0x06: u16, _ // unknown |
| 81 | + 0x08: [16]i32, arguments // Command arguments |
| 82 | + 0x48: u16, _ // unknown |
| 83 | +} |
| 84 | +``` |
| 85 | + |
| 86 | +# Command opcodes |
2 | 87 |
|
3 | 88 | All instructions return a status of `0` to the interpreter, unless otherwise noted.
|
4 | 89 |
|
|
0 commit comments