General Vritual Machine architecture

From Final Fantasy XII Wiki
Revision as of 09:04, 16 July 2019 by Admin (talk | contribs)
Jump to navigation Jump to search
VM's general specifications
Type stack based
Integer registers 4 (I0 to I3)
Float registers 4 (F0 to F3)
Special registers 3 (X, Y, A)
Number of instructions 100
Maximum stack size unknown
Number of calls ~2000

Final Fantasy XII contains a stack based virtual machine that runs field and event scripts. The implementation seems to be exactly the same starting with Japanese PS2 release, through PS4, PC and Nintendo Switch versions. The only thing that changes are available calls. Each subsequent version supports all previous calls and includes a few dozen of new ones at most.


Even though the VM contains a set of registers, they are used either by compiler or have only quality of life purpose (so it is not needed to declare variables for iterators or temporary storage). All except a few instructions operate solely on stack.

Immediates

Immediates are always 16bit wide integers. In all but one case their values should be treated as unsigned type, the only exception being PUSHII opcode, for which the immediate is always signed 16bit.

If a value greater than 32767 or lower than -32768 is needed, it has to be placed in a special integer table that can be accessed by PUSHI opcode. This means that in a single script file, there can't be more than 65536 unique integer values outside of signed 16bit range. It shouldn't ever become a problem, but there are methods to use more values (arrays with initializer list).

Floating point values are never immediates. Instead, they're stored in similar tables as integers and can be accessed by PUSHF opcode. This means that, just as in case of integers, there cannot be more than 65536 unique floating point values in a single script file. All floating point values are 32bit IEEE754 single precision.

Registers

VM provides the following set of registers:

  • 4 integer registers (I0 to I3, accessed by PUSHI0, PUSHI1, PUSHI2, PUSHI3, POPI0, POPI1, POPI2, POPI3 opcodes)
  • 4 floating point registers (F0 to F3, accessed by PUSHF0, PUSHF1, PUSHF2, PUSHF3, POPF0, POPF1, POPF2, POPF3 opcodes)
  • 3 special purpose registers (X, Y, A accessed by PUSHX, POPX, PUSHY, POPY, PUSHA, POPA and various conditional and calling opcodes)

Special register X is used mostly by if-type conditional jump instructions.

Special register Y is used mostly by switch-case conditional jump instructions.

Special register A is used mostly by call-type instructions.

Because of that, even though it is possible to use special registers directly, it is not recommended.

Variables

TBC

REQ tables

TBC

Calls

TBC