open-story-teller/docs/dev-firmware-micro-vm.md

134 lines
6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Micro VM
The stories created through the official Story Editor using graphical nodes are compiled into a binary executable. This binary is then interpreted by a micro virtual machine embedded in the OpenStory firmware.
Here is a description of that VM.
# Registers
| name | number | type | call-preserved |
|-------|--------|----------------------------------|-----------|
| r0-r9 | 0-9 | general-purpose | N |
| t0-t9 | 10-19 | temporary registers | Y |
| pc | 20 | program counter | Y |
| sp | 21 | stack pointer | Y |
| ra | 22 | return address | N |
Registers that are preserved means that the VM will store them on the stack before the `call` operation. Then, after the return (`ret`), theses registers are restored.
Registers that are not preserved must be saved manually (by writing code) by the user before using them.
# Instructions
| Instruction | Encoding | Arguments (bytes) | Description | Example |
|------- |-------- |------------- |-----------| -----|
| nop | 0 | 0 | Do nothing |  |
| halt | 1 | 0 | Halt execution |  |
| syscall | 2 | 1 | System call handled by user-registered function. Machine specific. Argument is the system call number, allowing up to 256 system calls. |  `syscall 42` |
| lcons | 3 | 4 | Store an immediate value in a register. Can also store a variable address. | `lcons r0, 0xA201d800`, `lcons r2, $DataInRam` |
| mov | 4 | 2 | Copy a register in another one. | `mov r0, r2` |
| push | 5 | 1 | Push a register onto the stack. | `push r0` |
| pop | 6 | 1 | Pop the first element of the stack to a register. | `pop r7` |
| store | 7 | 3 | Copy a value from a register to a ram address located in a register with a specified size | `store @r4, r1, 2` ; Copy R1 to address of R4, 2 bytes |
| load | 8 | 3 | Copy a value from a ram address located in a register to a register, with a specific size. | `load r0, @r3, 1` ; 1 byte |
| add | 9 | 2 | sum and store in first reg. | `add r0, r2` |
| sub | 10 | 2 | subtract and store in first reg. | ` sub r0, r2` |
| mul | 11 | 2 | multiply and store in first reg . | `mul r0, r2` |
| div | 12 | 2 | divide and store in first reg. | `div r0, r2` |
| shiftl | 13 | 2 | logical shift left. | `shl r0, r1` |
| shiftr | 14 | 2 | logical shift right. | `shr r0, r1` |
| ishiftr | 15 | 2 | arithmetic shift right (for signed values). | `ishr r0, r1` |
| and | 16 | 2 | and two registers and store result in the first one. | `and r0, r1` |
| or | 17 | 2 | or two registers and store result in the first one. | `or r0, r1` |
| xor | 18 | 2 | xor two registers and store result in the first one. | `xor r0, r1` |
| not | 19 | 1 | not a register and store result. | ` not r0` |
| call | 20 | 1 | Set register RA to the next instruction and jump to subroutine, must be a label. | `call .media` |
| ret | 21 | 0 | return to the address of last callee (RA). | `ret` |
| jump | 22 | 1 | jump to address (can use label or address). | `jump .my_label` |
| jumpr | 23 | 1 | jump to address contained in a register. | `jumpr t9` |
| skipz | 24 | 1 | skip next instruction if zero. | `skipz r0` |
| skipnz | 25 | 1 | skip next instruction if not zero. | `skipnz r2` |
| eq | 26 | 2 | compare two registers for equality, result in first | `eq r4, r0, r1 ; equivalent to C code: r4 = (r0 == r1) ? 1 : 0` |
| gt | 27 | 2 | compare if first register is greater than the second, result in first | `gt r4, r0, r1` |
| lt | 28 | 2 | compare if first register is less than the second, result in first | `lt r4, r0, r1` |
# System calls
The story player machine supports the following system calls:
## SYSCALL 1 (Play media)
This system call is used to play media. Use R0 and R1 to pass arguments:
- R0 is for the image:
- if zero, clear the screen
- Otherwise pass the address in ROM or RAM where is stored the image filename
- R1 is for the sound:
- if zero, do not play anything
- Otherwise pass the address in ROM or RAM where is stored the sound filename
The file must be stored in the `/assets` subdirectory of the current story.
The syscall do not blocks. User must wait for `end of sound` event if necessary.
## SYSCALL 2 (wait event)
This system call is used to wait for machine events. Use R0 to mask events to wait for (events not selected are ignored).
| Event | Bit |
|------- |-------- |
| OK button | 0 |
| Previous button | 1 |
| Next button | 2 |
| Up button | 3 |
| Down button | 4 |
| Home button | 5 |
| Select button | 6 |
| Start button | 7 |
| Stop button | 8 |
| Pause button | 9 |
| End of audio | 10 |
Example:
```
mov r0,
```
# Assembler
Basic grammar
------------------
Example:
```asm
; ---------------------------- Base node Type: Transition
.mediaEntry0004:
lcons r0, $fairy
lcons r1, $la_fee_luminelle
syscall 1
lcons r0, .mediaEntry0006
ret
```
Global variables
------------------
Example:
```asm
$yourLabel DC8 "a string", 5, 4, 8 ; Déclaration de constantes
$MaVar DV32 14 ; Variable en RAM : 14 emplacements de taille 32-bits
```
Grammar:
| Type | First column | Second column | Third column | Next columns |
|------- |------- |-------- |------------- |-----------|
| ROM constant | label statring with dollar sign | DC + base size (8, 16, 32) | constatant value (integer or string, surrounded by double quotes) | more values, separated by a coma |
| RAM variable | label statring with dollar sign | DV + base size (8, 16, 32) | Size of the array (number of elements) | - |