GOOL Interpreter

From Crash Bandicoot Hacking Wiki
Revision as of 09:59, 30 July 2015 by Wikia>WurlyFox (Created page with "In the Crash games, the GOOL Interpreter is responsible for interpreting an object's executable bytecode. This bytecode instructs the interpreter to perform a specific sequenc...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

In the Crash games, the GOOL Interpreter is responsible for interpreting an object's executable bytecode. This bytecode instructs the interpreter to perform a specific sequence of operations that can conditionally or unconditionally alter specific characteristics of the object (ex. appearance, location, status, etc.), and should ultimately render the object according to its changing characteristics. As a result, the player observes a lively, animated, and interactive enemy, box, collectible item, or whatever other kind of in-game object it may be.

Operation

A single interpretation of an object's bytecode consists of the following steps:

  1. Fetch the instruction at the object's program counter location
    • Read the instruction at the object's program counter location
    • Point the object's program counter to the location of the following instruction
  2. Perform the operation specified by the fetched instruction
  3. Continue repeating steps 1 and 2 until a suspending instruction is fetched

(A suspending instruction is typically either a RET, which marks the end of a block, or ANIF/ANIS, which change the object's current frame of animation.)

UNFINISHED

The main purpose of instantiation for an object is so that, elsewhere among the game code (by a call to the intepreter routine), the interpreter can begin to interpret its bytecode. Thus, the GOOL bytecode interpreter interprets or executes an object by sequentially fetching instructions (i.e. unsigned longs) located in its bytecode. Additionally, for the interpreter to perform those instructions, the object needs a certain amount of its own stack memory to store the results of their operations and/or to read and use as the operands for subsequent operations.

The GOOL bytecode interpreter routine expects an object that knows the following:

  • Where to take instruction = object's program counter - the location in the object's bytecode from which the interpreter shall begin interpretation or its process of sequentially fetching instructions and performing their corresponding operations
  • Where to commit to/read from memory = object's stack pointer - wherein the object's memory the interpreter shall begin pushing the results of/popping the operands for interpreted instructions
  • How to take instruction = interpreter status flags - how the flow of interpretation might be affected by various instructions

An object determines -where- it should begin taking instruction based on the -kind- of interpretation that shall be performed. Up to 5 distinct interpretations of an object's code can

occur in a single iteration of the main game loop; equivalently, the GOOL bytecode interpreter 

routine ('interpret()') can be called on the same object from up to 5 distinct locations in a single 

iteration of the main game loop: 


  MAIN LOOP:

  {

     ...

   2) or 5)

     ...

       initObject(object, ...)

         changeState(object, ...)

           ...

           newFrame(object)

           object->process.pc = object->process.headBlock;

           interpret(object, 3, &ret) // # 1

           ...

          ...


        issueEvent(sender, object, ...)

          -if there is an event service routine for the object (in its current state)

            ...

            newFrame(object);

            object->process.pc = object->process.eventBlock;

            interpret(object, 8, &event); // # 2


          -if event is non-state changing event

            ...

            newFrame(object);

            object->process.pc = gool_CODE(object, event);

            interpret(object, 3, &ret);  // # 3


          -else

            changeState(object, ...);

   9) Execute, animate, and render primitives for all objects (includes physics and collision engine)

        sub_8001D5EC - handleObjects()

          for each existing object do:

            ...

            -if at least one object frame worth of time for this object has elapsed since the following

            has been performed (i.e. since the object has last executed its trans block):


              newFrame(object);

              object->process.pc = object->process.transBlock;

              interpret(object, 3, &ret)  // # 4


              -if at least n ticks have elapsed, where n is given by the 'wait' operand of the most recently 

               suspending animation type instruction of the object's code block: 


               interpret(object, 4, &ret);  // # 5

              ...

  }


Thus, a potential sequence of instruction reads as a result of multiple calls to the interpret 

routine for the same object in one iteration of the main game loop could be: 


Offset/address | Instruction

---------------|-------------

headBlock: 0x0 |      N

           0x4 |      N

           0x8 |      N

           0xC |      S

.....          |     

eventBlock:0x34|      N

           0x38|      N

           0x3C|      S

.....          |

transBlock:0x50|      N

           0x54|      N

           0x58|      N

           0x5C|      N

           0x60|      N

           0x64|      N

           0x68|      S

.....          |

codeBlock: 0x70|      N

           0x74|      N

           0x78|      N

           0x7C|      N

           0x80|      S


Where the offsets/addresses of the interpreted instructions from the object's instantiating 

executable entries' bytecode item are indicated in the left column along with labels at the offsets 

that are pointed to in their respective object fields of the same name, and whether the instructions 

either did not suspend execution-causing the next instruction in sequence to be read/interpreted 

(indicated by an N)-or did suspend execution-causing the interpreter routine to return to the callee 

(indicated by an S). 


These object fields/pointers (headBlock, eventBlock, transBlock, codeBlock) define, for some object, 

the absolute locations of 'blocks' in the object's code that the object's program counter will be 

changed to point at, prior to each respective type of interpretation [during the iteration of the 

game loop in which the object is created]. Equivalently, they define the respective entry points for 

4 separate -threads- of execution for an object-a head thread, an event thread, a trans thread, and 

a code thread. 3 of these object fields/pointers change whenever the object 'changes state', which 

is accomplished with the 'changeState()' routine. 

Opcode Name Encoding/Format Explicit GOOL ops

in

Explicit IMM. ops

in

Implicit STACK ops

in

Operation Implicit STACK out Explicit

GOOL ops out

Description
0/0x00 ADD 00000000RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L + R O add
1/0x01 SUB 00000001RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L - R O subtract
2/0x02 MUL 00000010RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L * R O multiply
3/0x03 DIV 00000011RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L / R O divide
4/0X04 CEQ 00000100RRRRRRRRRRRRLLLLLLLLLLLL L,R O = (L == R),

O = ((L ^ R) == 0)

O check if equal
5/0x05 ANDL 00000101RRRRRRRRRRRRLLLLLLLLLLLL L,R O = (L && R),

O = (L ? (R > 0) : 0)

O logical and
6/0x06 ORL 00000110RRRRRRRRRRRRLLLLLLLLLLLL L,R O = (L || R) O
logical or
7/0x07 ANDB 00000111RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L & R O bitwise and
8/0x08 ORB 00001000RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L | R O bitwise or
9/0x09 SLT 00001001RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L < R O set less than
10/0x0A SLE 00001010RRRRRRRRRRRRLLLLLLLLLLLL L,R O = (L <= R) O set less than or equal
11/0x0B SGT 00001011RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L > R O set greater than
12/0x0C SGE 00001100RRRRRRRRRRRRLLLLLLLLLLLL L,R O = (L >= R) O set greater than or equal
13/0x0D MOD 00001101RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L % R O modulo
14/0x0E XOR 00001110RRRRRRRRRRRRLLLLLLLLLLLL L,R O = L ^ R O exclusive or
15/0x0F TST 00001111RRRRRRRRRRRRLLLLLLLLLLLL L,R O = (((L & R) ^ R) == 0) O test bit
16/0x10 RND 00010000AAAAAAAAAAAABBBBBBBBBBBB A,B O = B+(rand() % (A - B)) O random
17/0x11 MOVE 00010001SSSSSSSSSSSSDDDDDDDDDDDD S D = S [D] move data
18/0x12 NOTL 00010010SSSSSSSSSSSSDDDDDDDDDDDD S D = (S == 0) D logical not
19/0x13 PATH 00010011AAAAAAAAAAAABBBBBBBBBBBB (A),B R = 0x100 [R,A] varies P B path progress
20/0x14 LEA 00010100SSSSSSSSSSSSDDDDDDDDDDDD S D = &S D load effective address
21/0x15 SHA 00010101RRRRRRRRRRRRLLLLLLLLLLLL L,R O = ((R < 0) ? (L >> -R)

: (L << R))

O arithmetic shift
22/0x16 PSHV 00010110AAAAAAAAAAAABBBBBBBBBBBB [A,[B]] [arg_buf = A]

I = A; J = B;

[I,[J]] push value to stack
23/0x17 NOTB 00010111SSSSSSSSSSSSDDDDDDDDDDDD D = ~S D bitwise not
24/0x18 MOVC 000110000000RRRRRRIIIIIIIIIIIIII R,C see docs O move code pointer
25/0x19 ABS 00011001SSSSSSSSSSSSDDDDDDDDDDDD S D = (S < 0) ? -S: S D absolute value
26/0x1A PAD 00011010000TDDDDSSPPBBBBBBBBBBBB B,P,S,D,T O = testctrls(instr,0) O test controller buttons
27/0x1B SPD 00011011VVVVVVVVVVVVBBBBBBBBBBBB V,B S = B + ((V*gvel) >> 10) S calculate speed
28/0x1C MSC 00011100PPPPSSSSSLLLXXXXXXXXXXXX X P,S,L various; see docs *** *** multi-purpose
29/0x1D PRS 00011101PPPPPPPPPPPPDDDDDDDDDDDD P,D large calc; see docs O driven sine wave
30/0x1E SSAW 00011110DDDDDDDDDDDDPPPPPPPPPPPP M,P O = (M + frameCount) % P O synchronized saw wave
31/0x1F RGL 00011111000000000000IIIIIIIIIIII I O = globals[I >> 8] O read global variable
32/0x20 WGL 00100000SSSSSSSSSSSSIIIIIIIIIIII I,S globals[I << 8] = *S write global variable
33/0x21 ANGD 00100001RRRRRRRRRRRRLLLLLLLLLLLL L,R O = angdist(L,R) angle between
34/0x22 APCH 00100010RRRRRRRRRRRRLLLLLLLLLLLL L,(R) S = 0x100 [R,S] O = approach(L,R,S) O approach a value
35/0x23 CVMR 00100011000IIIIIILLL000000000000 I,L O = obj.link[L].colors[I] color vector or matrix read
36/0x24 CVMW 00100011000IIIIIILLLCCCCCCCCCCCC C I,L obj.link[L].colors[I] = C color vector or matrix write
37/0x25 ROT 00100101RRRRRRRRRRRRLLLLLLLLLLLL L,(R) [R,S] O = rotate(L,R,S,0) O approach an angle
38/0x26 PSHP 001001100AAAAAAAAAAABBBBBBBBBBBB [A,[B]] I = &A; J = &B; [I,[J]] push pointer to stack
39/0X27 ANID 00100111FFFFFFFFFFFFDDDDDDDDDDDD F D=&obj.global.anim[F>>5] D set animation
128/0x80 DBG 10000000RRRRRRRRRRRRLLLLLLLLLLLL L,R debug print ops (beta only)
129/0x81 NOP 10000001000000000000000000000000 no operation
130/0x82 CFL 10000010TTCCRRRRRRIIIIIIIIIIIIII T,C,R,I general control flow
BRA 100000100000RRRRRRVVVVIIIIIIIIII R,V,I branch
BNEZ 100000100001RRRRRRVVVVIIIIIIIIII R,V,I branch not equal zero
BEQZ 100000100010RRRRRRVVVVIIIIIIIIII R,V,I branch equal zero
CST 100000100100RRRRRRSSSSSSSSSSSSSS R,S change state
CSNZ 100000100101RRRRRRSSSSSSSSSSSSSS R,S change state not zero
CSEZ 100000100110RRRRRRSSSSSSSSSSSSSS R,S change state equal zero
RET 100000101000RRRRRRIIIIIIIIIIIIII R,I return
131/0x83 ANIS 10000011HHTTTTTTSSSSSSSSSFFFFFFF F,S,T,H W change animation sequence
132/0x84 ANIF 10000100HHTTTTTTFFFFFFFFFFFFFFFF F T,H W change animation frame
133/0x85 VECA 10000101CCCTTTBBBAAAVVVVVVVVVVVV V T,A,B,C * ** multi-purpose vector calcs
134/0x86 JAL 10000110VVVV000000IIIIIIIIIIIIII I,V jump and link
135/0x87 EVNT 10000111LLLAAARRRRRREEEEEEEEEEEE E L,A,R send an event
136/0x88 RSTT 10001000TTCCRRRRRR************** R,C,T,* **
state return guard = true variant
137/0x89 RSTF 10001001TTCCRRRRRR************** R,C,T,* ** state return guard = false variant
138/0x8A CHLD 10001010AAAATTTTTTTTSSSSSSCCCCCC C,T,S,A [C],

arg[0 to A]

spawn children objects
139/0x8B NTRY 10001011TTTTTTTTTTTTEEEEEEEEEEEE T,E multi-purpose page operation
140/0x8C SNDA 10001100AAAAAAAAAAAABBBBBBBBBBBB A,B adjust audio levels
141/0x8D SNDB 10001101VVVVRRRRRRSSSSSSSSSSSSS
play sound
effect
142/0x8E VECB 10001110CCCTTTBBBAAAVVVVVVVVVVVV V T,A,B,C
multi-purpose vector calcs
143/0x8F EVNB 10001111LLLAAARRRRRREEEEEEEEEEEE E L,A,R
broadcast an event
144/0x90 EVNU 10010000LLLAAARRRRRREEEEEEEEEEEE E L,A,R

send event unknown variant
145/0x91 CHLF 10100000AAAATTTTTTTTSSSSSSCCCCCC C,T,S,A [C],

arg[0 to A]


spawn children objects;

no replacement if obj pool full

Specification Format

A AAAAAAAAAAAA AAAA AAA (EVNT/EVNU/EVNB) AAA (VECA/VECB)
Name Value A Argument Count Argument Count Vector A Index
Specification Format B BBBBBBBBBBBB BBBBBBBBBBBB (PAD) BBBBBBBBBBBB (SPD) BBB
Name Value B Controller Buttons Base Speed Vector B Index
Specification Format C CCCCCCCCCCCC CCCCCC CCC CC
Name Color Value Spawn Count Vector C Index Conditional Check Type
Specification Format D DDDDDDDDDDDD DDDDDDDDDDDD (PRS) DDDD
Name Destination Wave Phase Directional Buttons
Specification Format E EEEEEEEEEEEE (NTRY) EEEEEEEEEEEE (EVNT/EVNU/EVNB)
Name Entry Event
Specification Format F FFFFFFFFFFFFFFFF FFFFFFFFFFFF FFFFFFF
Name Animation Frame Animation Descriptor Offset Animation Frame

Specification Format

H HH
Name Horizontal Flip

Specification Format

I IIIIIIIIIIIIII IIIIIIIIIIII IIIIIIIIII IIIIII
Name Immediate Code Location Global Variable Index Immediate Branch Offset Color Index

Specification Format

L LLLLLLLLLLLL LLL
Name Left Operand Object Link Index

Specification Format

P PPPPPPPPPPPP PPPP PP
Name Wave Period Primary Operation Subtype Primary Check Type

Specification Format

R RRRRRRRRRRRR RRRRRR
Name Right Operand Object Register Index

Specification Format

S SSSSSSSSSSSSSS SSSSSSSSSSSS SSSSSSSSS SSSSSS
Name State Source Animation Sequence Index Subtype

Specification Format

SSSSS SS
Name Secondary Operation Subtype Secondary Check Type

Specification Format

T TTTTTTTTTTTT TTTTTTTT TTTTTT TTT
Name Operation Subtype (Object) Type Time Operation Subtype

Specification Format

TT T
Name Operation Subtype Truth Invert Toggle

Specification Format

V VVVVVVVVVVVV VVVV VVVV (SNDB)
Name Velocity Variable Count Volume

State Return Instruction Table

Opcode Name Encoding/Format Explicit

IMM. ops

in

Description
136/0x88 RSTT 10001000TTCCRRRRRR************** R,C,T,* state return guard = true variant
RST 100010000100RRRRRRSSSSSSSSSSSSSS R,S state return guard = true
RSNT 100010000101RRRRRRSSSSSSSSSSSSSS R,S state return if nonzero guard = true
RSZT 100010000110RRRRRRSSSSSSSSSSSSSS R,S state return if equal zero guard = true
RSCT 100010000111RRRRRRSSSSSSSSSSSSSS R,S state return eval prev cond guard = true
RNT 100010001000RRRRRRxxxxxxxxxxxxxx R null return guard = true
RNNT 100010001001RRRRRRxxxxxxxxxxxxxx R null return if nonzero guard = true
RNZT 100010001010RRRRRRxxxxxxxxxxxxxx R null return if equal zero guard = true
RNCT 100010001011RRRRRRxxxxxxxxxxxxxx R null return eval prev cond guard = true
GDT 100010001100RRRRRRxxxxxxxxxxxxxx R guard = true
GNT 100010001101RRRRRRxxxxxxxxxxxxxx R if nonzero guard = true
GZT 100010001110RRRRRRxxxxxxxxxxxxxx R if equal zero guard = true
GCT 100010001111RRRRRRxxxxxxxxxxxxxx R eval prev cond guard = true
GBNT 100010000001RRRRRRVVVVIIIIIIIIII R,V,I if nonzero guard = true else branch
GBZT 100010000010RRRRRRVVVVIIIIIIIIII R,V,I if equal zero guard = true else branch
137/0x89 RSTF 10001001TTCCRRRRRR************** R,C,T,* state return guard = false variant
RSF 100010000100RRRRRRSSSSSSSSSSSSSS R,S state return guard = false
RSNF 100010000101RRRRRRSSSSSSSSSSSSSS R,S state return if nonzero guard = false
RSZF 100010000110RRRRRRSSSSSSSSSSSSSS R,S state return if equal zero guard = false
RSCF 100010000111RRRRRRSSSSSSSSSSSSSS R,S state return eval prev cond guard = false
RNF 100010001000RRRRRRxxxxxxxxxxxxxx R null return guard = false
RNNF 100010001001RRRRRRxxxxxxxxxxxxxx R null return if nonzero guard = false
RNZF 100010001010RRRRRRxxxxxxxxxxxxxx R null return if equal zero guard = false
RNCF 100010001011RRRRRRxxxxxxxxxxxxxx R null return eval prev cond guard = false
GDF 100010001100RRRRRRxxxxxxxxxxxxxx R guard = false
GNF 100010001101RRRRRRxxxxxxxxxxxxxx R if nonzero guard = false
GZF 100010001110RRRRRRxxxxxxxxxxxxxx R if equal zero guard = false
GCF 100010001111RRRRRRxxxxxxxxxxxxxx R eval prev cond guard = false
GBNF 100010000001RRRRRRVVVVIIIIIIIIII R,V,I if nonzero guard = false else branch
GBZF 100010000010RRRRRRVVVVIIIIIIIIII R,V,I if equal zero guard = false else branch