Wikifang:Network Translation Patchsite/BugVM

From Wikifang, a definitive guide to Telefang, Dino Device and Bugsite
Jump to navigation Jump to search

Bugsite contains a virtual machine which executes all (non-IRQ) game logic. It is a stack-based virtual machine with a large number of opcodes specific to the game.

Data and Link Stacks

Two stacks are managed by the VM: a link stack and a data stack. The link stack ($C100) supports up to $3F call frames of 4 bytes each, which is manipulated entirely by the call, jump-far, and return opcodes. The data stack ($C200) supports up to $55 data items of 3 bytes each. Each data item consists of a little-endian 16-bit word followed by a tag byte, which specifies if it's...

  • $3D an immediate value
  • $1D a word index into the indirect memory array
  • $1E a bit index into the predicate array

Data items are pushed onto the stack as immediate values and then cast to indirect or predicate offsets as necessary. Both stacks grow upwards from their base address.

Indirect & Predicate Memory

BugVM allows direct access (read and write) to indirect and predicate memory. Indirect memory covers WRAM3:$C400 to WRAM3:$D7FF, and is indexed using word offsets. Predicate memory covers WRAM3:$D800 to WRAM3:$DFFF and is indexed as a massive bitfield.

Indirect and predicate memory can be saved to and loaded from SRAM using opcodes $47 and $48, along with additional data in SRAM.

Known Indirect Memory Slots

Index WRAM Addr. Name Purpose
$12 $C424 W_BugVM_StringArena Stores the current location of the end of the string-builder arena, used by the DSTR opcode to store embedded string data.

Linkage Directory

Code and graphical resources exist entirely within sections, which can be referred to by their 16-bit linkage identifier. The linkage identifier indexes a directory starting from $A:$4000, with $800 8-byte directory entries per bank. In practice, while the directory could extend all the way across 8 banks, only 2 are used for the directory. (Effectively, linkages above $1000 are invalid and will horribly crash the game.) Directory entries appear to be stored in order of where their data is stored in ROM.

Each directory index contains a bank index, byte offset into that bank (0 means a pointer of $4000), and total size; with at least graphical resource loads capable of handling sections that span multiple banks. The remaining three bytes are padding and are always zero. There appear to be about 36 unused directory entries from linkage $FDC all pointing to $7F:$70FF with a size of zero.

Initial State

Execution of BugVM always starts from the beginning of linkage $0. Indirect and predicate memory is set to $0 upon game initialization.

Instruction Set

BugVM takes instructions as 8-bit opcodes which can optionally accept additional parameters. Most opcodes take arguments from the stack, rather than from the instruction stream. Native implementations for a particular opcode are referenced from the opcode table at $3E00, reproduced below:

x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x NOP
$5E9
NOP
$5E9
NOP
$5E9
???
$671
NOP
$5E9
NOP
$5E9
STR
$68C
SUML
$6C0
ANDL
$6CA
OR
$6D7
XOR
$6E2
AND
$6ED
CMP_EQ
$6F8
CMP_NEQ
$705
CMP_LT
$712
CMP_LEQ
$723
1x CMP_GT
$752
CMP_GEQ
$763
???
$772
SLA
$784
SUB
$796
ADD
$7A1
MOD
$7A9
DIV
$7C3
MUL
$7ED
NOP_19
$80B
NOP_1A
$80C
NOP_1B
$80D
NOP_1C
$80E
INDIR
$80F
PRED
$820
NOP
$5E9
2x NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
NOP
$5E9
POPALL
$831
NOP
$5E9
NOP
$5E9
NOP_2F
$835
3x NOP_30
$836
NOP_31
$837
NOP_32
$838
NOP_33
$839
NOP_34
$83A
NOP_35
$87B
NPREF
$87C
JMPT
$887
JMP
$8AC
RET
$8BB
NOP_3A
$8DB
NOP_3B
$8DC
NOP_3C
$8DD
IMMED
$8DE
DSTR
$941
JAL
$8F0
4x
5x
6x
7x
8x
9x
Ax
Bx
Cx
Dx
Ex
Fx

Boolean Logic & Comparison Operators

As convention for this table we treat zero as boolean TRUE and one as boolean FALSE. Other non-zero values are treated as FALSE, but boolean opcodes will not return nonstandard values.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
SUML
(SUM Logical)
$07 $6C0 None arg1, arg2 (TOP) -> bool (TOP) Add arg1 and arg2. Push TRUE if result is zero, FALSE if non-zero.
ANDL
(AND Logical)
$08 $6CA None arg1, arg2 (TOP) -> bool (TOP) Bitwise-AND arg1 and arg2. Push TRUE if result is zero, FALSE if non-zero.
CMP_EQ
(CoMParison EQual)
$0C $6F8 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if both arguments are equal, FALSE otherwise.
CMP_NEQ
(CoMParison Not EQual)
$0D $705 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if both arguments are not equal, FALSE otherwise.
CMP_LT
(CoMParison Less Than)
$0E $712 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is less than arg2, FALSE otherwise.
CMP_LEQ
(CoMParison Less or EQual)
$0F $723 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is less than or equal to arg2, FALSE otherwise.
CMP_GT
(CoMParison Greater Than)
$10 $752 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is greater than arg2, FALSE otherwise.
CMP_GEQ
(CoMParison Greater or EQual)
$11 $763 None arg1, arg2 (TOP) -> bool (TOP) Compare arg1 and arg2. Push TRUE if arg1 is greater than or equal to arg2, FALSE otherwise.

Bitwise logic

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
OR
(bitwise OR)
$09 $6D7 None arg1, arg2 (TOP) -> value (TOP) Bitwise-OR arg1 and arg2 as the return value.
XOR
(bitwise eXclusive OR)
$0A $6E2 None arg1, arg2 (TOP) -> value (TOP) Bitwise-XOR arg1 and arg2 as the return value.
AND
(bitwise AND)
$0B $6ED None arg1, arg2 (TOP) -> value (TOP) Bitwise-AND arg1 and arg2 as the return value.
SLA
(Shift-Left Arithmetic)
$13 $784 None bits, shift (TOP) -> value (TOP) Shift bits left, shift times, while inserting zero bits, to produce value.

Arithmetic

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
SUB
(SUBtraction)
$14 $796 None minuend, subtrahend (TOP) -> difference (TOP) Subtract subtrahend from minuend to produce difference.
ADD
(ADDition)
$15 $7A1 None addend1, addend2 (TOP) -> sum (TOP) Add addend1 to addend2 to produce sum.
MOD
(MODulo)
$16 $7A9 None dividend, divisor (TOP) -> remainder (TOP) Integer-divide dividend by divisor and return only the remainder.
DIV
(DIVide)
$17 $7C3 None dividend, divisor (TOP) -> quotient (TOP) Integer-divide dividend by divisor and return only the quotient.
MUL
(MULtiply)
$18 $7ED None multiplicand, multiplier (TOP) -> product (TOP) Multiply multiplicand by multiplier to produce the product.

Memory & Stack Manipulation

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
STR
(SToRe)
$06 $68C None &address, value (TOP) -> (TOP) Store the value at the memory location referenced by &address. The exact memory operations performed depend on the target of *address.

If address is an indirect index, the memory location referenced by *address will be set to value.

If address is a predicate index, the bit referenced by *address will be set or reset based on if value is zero or non-zero.

It is illegal to STR into an immediate value, and doing so will cause the VM to halt operation.

INDIR
(INDIRect)
$1D $80F None immed (TOP) -> &address (TOP) Cast the value immed into an indirect memory index &address.
PRED
(PREDicate)
$1E $820 None immed (TOP) -> &pred (TOP) Cast the value immed into a predicate memory index &pred.
POPALL
(POP ALL)
$2C $831 None anything (TOP) -> (EMPTY) Empty the stack.
IMMED
(IMMEDiate)
$3D $8DE immed (16b) (TOP) -> immed (TOP) Push immed onto the data stack as an immediate value.
DSTR
(Declare STRing)
$3E $941 string (null-terminated) (TOP) -> straddr (TOP) Copy null-terminated string data from the instruction stream into the string-building arena referred to by $C424.

The address of the newly copied string data will be pushed onto the data stack as an immediate value.

Execution Control

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
JMPT
(JuMP if True)
$37 $887 offset (16b) bool (TOP) -> (TOP) Jump to a new offset within the current linkage section if bool is TRUE.
JMP
(JuMP)
$38 $8AC offset (16b) None Jump to a new offset within the current linkage section.
RET
(RETurn)
$39 $8BB None None Return to the previously linked return address.
JAL
(Jump And Link)
$3F $8F0 offset (16b) None Jump to a new offset within the current linkage section. Store the offset of the next instruction on the link stack.

NOP and NOP-alikes

BugVM contains a number of opcodes which do nothing, including both a single implementation of a NOP opcode used to fill in blank spots in the table as well as individual implementations which presumably did something in the past.

Opcode Encoding(s) Native Impl. Operand Args Stack Args Description
NOP
(Null OPeration)
Too many to list $5E9 None None Does nothing.
NOP_19
(Null OPeration)
$19 $80B None None Does nothing.
NOP_1A
(Null OPeration)
$1A $80C None None Does nothing.
NOP_1B
(Null OPeration)
$1B $80D None None Does nothing.
NOP_1C
(Null OPeration)
$1C $80E None None Does nothing.
NOP_2F
(Null OPeration)
$2F $835 None None Does nothing.
NOP_30
(Null OPeration)
$30 $836 None None Does nothing.
NOP_31
(Null OPeration)
$31 $837 None None Does nothing.
NOP_32
(Null OPeration)
$32 $838 None None Does nothing.
NOP_33
(Null OPeration)
$33 $839 None None Does nothing.
NOP_34
(Null OPeration)
$34 $83A None None Does nothing.
NOP_35
(Null OPeration)
$35 $87B None None Does nothing.
NPREF
(Null PREFix)
$36 $87C opcode, ??? None Executes the next opcode as normal.

This would appear to be just another NOP, but it's native implementation actually loads and executes the next byte as an opcode. Hence, it works like a prefix byte that does nothing.

Perhaps in a previous revision of the game, NPREF had a use.

NOP_3A
(Null OPeration)
$3A $8DB None None Does nothing.
NOP_3B
(Null OPeration)
$3B $8DC None None Does nothing.
NOP_3C
(Null OPeration)
$3C $8DB None None Does nothing.