The PSL Implementation Guide.

By Steve Baker

Introduction

This document describes the virtual machine that the PSL byte code interpreter implements.

The machine has 65536 bytes of instruction memory (and hence, 16 bit code addresses) and 256 variables (and hence 8 bit data addresses). Each variable can be a 32 bit integer, an IEEE single precision float or a character string of arbitary length.

In addition, there is a 256 element stack - each entry of which can contain any PSL data type.

The machine has just two registers - the Program Counter (PC) and the Stack Pointer (SP) - neither of which are accessible to running programs directly.

The Instruction Set

Each instruction consists of a one byte opcode and some number of bytes of data.

The hex numbers for these opcodes are listed in plib/src/psl/pslOpcodes.h

OPCODE_BAD

INTRUCTION BYTES: 1
EFFECT: Produces a 'Suspicious Opcode' error message and halts the program.
Generally, programs that run amok for some reason (eg an error in the compiler) will hit a zero byte fairly soon afterwards. Hence instruction 0x00 is reserved to be the BAD instruction. Other unrecognised instructions are also flagged as errors - but it's useful to explicitly reserve opcode 0x00 for this function due to the high probability of it being executed by broken programs.

OPCODE_LINE_NUMBER

INTRUCTION BYTES: 3
EFFECT: Updates the 'current line number' from the two bytes embedded in the instruction.

OPCODE_PUSH_INT_CONSTANT

INTRUCTION BYTES: 5
EFFECT: Takes four bytes from the instruction and pushes them onto the stack as an integer.

OPCODE_PUSH_FLOAT_CONSTANT

INTRUCTION BYTES: 5
EFFECT: Takes four bytes from the instruction and pushes them onto the stack as a float.

OPCODE_PUSH_STRING_CONSTANT

INTRUCTION BYTES: 1 + strlen string + 1
EFFECT: Takes a null-terminated string from the instruction stream and pushes it onto the stack.

OPCODE_GET_PARAMETER

INTRUCTION BYTES: 3
EFFECT: Fetches the value of a function's parameter from the depths of the stack and puts it into a local variable.

The second byte of the instruction is the index of the variable. The third byte is a small integer offset - which is the number of the parameter you want.

Look at the number two down from the top of the stack (which should be the number of parameters of a recently called function).

Now copy the stack element at sp - ( nargs + 2 ) + offset into the variable.

OPCODE_POP

INTRUCTION BYTES: 1
EFFECT: Throws away the top element of the stack.

OPCODE_CALLEXT

INTRUCTION BYTES: 3
EFFECT: The second byte of the instruction is the index of a PSL 'extension function', the third is the number of arguments being passed to it.

Pop that number of values off the stack and pass them to the extension function.

Call the extension function. Push the result onto the stack.

OPCODE_CALL

INTRUCTION BYTES: 6
EFFECT: [The number of aguments will already have been pushed onto the stack.]

The four bytes after the instruction is the function address. The fifth byte is the number of arguments.

Push return address.
PC = address of function.

popNumber ( &result ) ;
   pc = popInt () ;
   nargs = popInt () ;
   popVoid ( nargs ) ;
pushNumber ( &result ) ;

OPCODE_STACK_DUPLICATE

INTRUCTION BYTES: 1
EFFECT: Duplicate the top element of the stack.

OPCODE_EXCHANGE

INTRUCTION BYTES: 1
EFFECT: Exchange the top two elements of the stack.

OPCODE_LESS

OPCODE_LESSEQUAL

OPCODE_GREATER

OPCODE_GREATEREQUAL

OPCODE_NOTEQUAL

OPCODE_EQUAL

OPCODE_ADD

OPCODE_SUB

OPCODE_SHIFTLEFT

OPCODE_SHIFTRIGHT

OPCODE_OROR

OPCODE_ANDAND

OPCODE_OR

OPCODE_AND

OPCODE_XOR

OPCODE_DIV

OPCODE_MOD

OPCODE_MULT

INTRUCTION BYTES: 1
EFFECT: Pop the top element from the stack and operate on it and the next element down - leaving the result on the stack in it's place. So (for example) if the operation was 'SUB' (Subtract), and A is on top of the stack and B is beneath it - then the result of this operation would be to leave (B-A) on the stack with no sign of either A or B.

The 'ADD' operator also works with strings by concatenating them.

OPCODE_NOT

OPCODE_TWIDDLE

OPCODE_NEG

INTRUCTION BYTES: 1
EFFECT: Perform the C unary '!', '~' or '-' operator on the top element of the stack.

OPCODE_PAUSE

INTRUCTION BYTES: 1
EFFECT: Informs application program that the script wishes to be paused until next frame.

OPCODE_HALT

INTRUCTION BYTES: 1
EFFECT: Informs the application that the script wishes to halt. Even if the application ignores this request, the script will continue looping at this location for ever.

OPCODE_PEEK_JUMP_TRUE

OPCODE_PEEK_JUMP_FALSE

INTRUCTION BYTES: 3
EFFECT: The two bytes at the end of the instruction contain an address. Inspect the number off the top of the stack (without popping it) - and branch to the specified instruction if the value is TRUE (or FALSE as applicable).

OPCODE_JUMP_TRUE

OPCODE_JUMP_FALSE

INTRUCTION BYTES: 3
EFFECT: The two bytes at the end of the instruction contain an address. POP the number off the top of the stack (without popping it) - and branch to the specified instruction if the value is TRUE (or FALSE as applicable).

OPCODE_JUMP

INTRUCTION BYTES: 3
EFFECT: The two bytes at the end of the instruction contain an address. Jump to that address.

OPCODE_PUSH_VARIABLE

INTRUCTION BYTES: 2
EFFECT: The second byte of the instruction is the index of a variable. The value of that variable is pushed onto the stack.

OPCODE_POP_ADD_VARIABLE

OPCODE_POP_SUB_VARIABLE

OPCODE_POP_MUL_VARIABLE

OPCODE_POP_MOD_VARIABLE

OPCODE_POP_DIV_VARIABLE

OPCODE_POP_AND_VARIABLE

OPCODE_POP_OR_VARIABLE

OPCODE_POP_XOR_VARIABLE

OPCODE_POP_SHL_VARIABLE

OPCODE_POP_SHR_VARIABLE

INTRUCTION BYTES: 1
EFFECT: Three things are on the stack when this function is called.
The thing on top is the result of an expression evaluation.
The thing beneath that is the index of a variable.
The thing beneath that is the dimension of the variable.
The value is added to/subtracted from/multiplied by/etc the variable - and stored back into the variable.
The new value of the variable is left on the stack.

OPCODE_POP_VARIABLE

INTRUCTION BYTES: 1
EFFECT: Three things are on the stack when this function is called.
The thing on top is the result of an expression evaluation.
The thing beneath that is the index of a variable.
The thing beneath that is the dimension of the variable.
The value is stored into the variable.
The new value of the variable is left on the stack.

OPCODE_SET_INT_ARRAY

OPCODE_SET_FLOAT_ARRAY

OPCODE_SET_STRING_ARRAY

INTRUCTION BYTES: 2
EFFECT: The second byte of the instruction is the index of an array variable.
On the top of the stack is an integer.
This instruction allocates that number of elements of storage to the array.

OPCODE_SET_INT_VARIABLE

OPCODE_SET_FLOAT_VARIABLE

OPCODE_SET_STRING_VARIABLE

INTRUCTION BYTES: 2
EFFECT: The second byte of the instruction is the index of a variable.
That variable is created, set to the appropriate type and initialised appropriately.

OPCODE_FETCH

INTRUCTION BYTES: 1
EFFECT: The index of a variable is on top of the stack.
The thing beneath that is the dimension of the variable.
Replace those with the value of that variable.

OPCODE_INCREMENT_FETCH

OPCODE_DECREMENT_FETCH

INTRUCTION BYTES: 1
EFFECT: The index of a variable is on top of the stack.
The thing beneath that is the dimension of the variable.
Replace those with the value of that variable. Post-increment/decrement the variable.

OPCODE_INCREMENT_LVALUE

OPCODE_DECREMENT_LVALUE

INTRUCTION BYTES: 1
EFFECT: The index and dimension of a variable is on top of the stack.
Increment/decrement the variable leaving the stack contents undisturbed.

Steve J. Baker. <sjbaker1@airmail.net>