Virtual machine definition

Virtual machine definition


Document formatted by vherva at Fri Apr 24 11:23:51 1998 on the host schemestation. This document is produced by the SchemeStation project during the Tik-76.115 course.

1 Introduction

SCHEMESTATION virtual machine is supposed to be a multipurpose virtual machine with some specific support for the scheme language. The instruction set has been derived from SICP(*) and HUTScheme (**) virtual machine constructions with some appropriate modifications. The basic architecture of the SCHEMESTATION virtual machine is a register machine (12 general purpose registers) with a garbage collected and list-based (typed) memory (/heap).

2 Registers

There are 12 general purpose registers available in the SCHEMESTATION virtual machine. Registers are named R1-R16. Registers R13-R16 are reserved for internal use by the message queue (R13), exception handler (R14), stack (R15) and program counter (R16). Registers R13-R16 should not normally be tampered with by user programs -- that is, use at your own risk. Each register holds 64 bits of data and an 8bit type tag. The default procedure calling convention consists of putting the number of arguments to register R1, possible first three (3) arguments to registers R2 - R4, a vector of all other arguments to register R5 and the return value to R6. This calling convention is used for example in conjunction with the exception handler. Registers R7 - R9 are callee-saved and registers R10 - R12 caller-saved. The called procedure can modify registers R1 - R6.

3 Instructions

The actual instruction numbers are defined elsewhere (SchemeStation VM instruction numbers and argument types).

3.1 Heap

3.1.1 ALLOC-INTEGER Rdest

Allocate an integer from the heap and put the address of the integer to Rdest.

3.1.2 ALLOC-FLOAT Rdest

Allocate a float from the heap and put the address of the float to Rdest.

3.1.3 ALLOC-BOOLEAN Rdest

Allocate a boolean from the heap and put the address of the boolean to Rdest.

3.1.4 ALLOC-PAIR Rdest

Allocate a pair from the heap and put the address of the pair to Rdest.

3.1.5 ALLOC-PAIR-TAGGED Rdest, tag

Allocate a tagged pair from the heap with tag tag and put the address of the pair to Rdest.

3.1.6 ALLOC-VECTOR Rdest, Rsize

Allocate a vector of size Rsize from the heap and put the address of the vector to Rdest.

3.1.7 ALLOC-VECTOR-IMMEDIATE Rdest, size

Allocate a vector of size size from the heap and put the address of the vector to Rdest.

3.1.8 ALLOC-VECTOR-TAGGED Rdest, Rsize, tag

Allocate a tagged vector of size Rsize and tag tag from the heap and put the address of the vector to Rdest.

3.1.9 ALLOC-SHARED-BIT-STRING Rdest, Rsize

Allocate a shared bit string of size Rsize from the heap and put the address of the bit string to Rdest.

3.1.10 ALLOC-SHARED-BIT-STRING-TAGGED Rdest, Rsize, tag

Allocate a tagged shared bit string of size Rsize and tag tag from the heap and put the address of the bit string to Rdest.

3.1.11 ALLOC-PRIVATE-BIT-STRING Rdest, Rsize

Allocate a private bit string of size Rsize from the heap and put the address of the bit string to Rdest.

3.1.12 ALLOC-PRIVATE-BIT-STRING-TAGGED Rdest, Rsize, tag

Allocate a tagged private bit string of size Rsize and tag tag from the heap and put the address of the bit string to Rdest.

The difference between shared and private bit strings is the fact that an access to private bit strings generates a copy of the string, but an access to shared bit string references always the same bit string. This means that modifying a shared bit string can be seen from all references of that particular bit string, whereas modifying a private bit string can only be seen from that particular point of access.

3.1.13 INTEGER-SET! Rdest, Rvalue

Set the value of Rdest to integer Rvalue.

3.1.14 FLOAT-SET! Rdest, Rvalue

Set the value of Rdest to float Rvalue.

3.1.15 BOOLEAN-SET! Rdest, Rvalue

Set the value of Rdest to boolean Rvalue.

3.1.16 PAIR-SET-CAR! Rdest, Rsource

Set the first element of the pair Rdest to Rsource.

3.1.17 PAIR-SET-CDR! Rdest, Rsource

Set the second element of the pair Rdest to Rsource.

3.1.18 PAIR-GET-CAR Rdest, Rsource

Set the Rdest to the value of the first element of a pair Rsource.

3.1.19 PAIR-GET-CAR-OR-BLOCK Rdest, Rsource

Set the Rdest to the value of the first element of a pair Rsource, however, if the value of the first element is null, block execution until it changes value.

3.1.20 PAIR-GET-CDR Rdest, Rsource

Set the Rdest to the value of the second element of a pair Rsource.

3.1.21 VECTOR-SET! Rdest, Rindex, Rvalue

Set the Rindexth value in vector Rdest to Rvalue.

3.1.22 VECTOR-GET Rdest, Rsource, Rindex

Put the Rindexth value in vector Rsource to Rdest.

3.1.23 VECTOR-LEN Rdest, Rsource

Set the Rdest to the length of the vector Rsource.

3.1.24 COPY-PAIR Rdest, Rsource

Make a copy of the pair in Rsource to Rdest.

3.1.25 COPY-VECTOR Rdest, Rsource

Make a copy of the vector in Rsource to Rdest.

3.1.26 COPY-BIT-STRING Rdest, Rsource

Make a copy of the bit string in Rsource to Rdest.

3.1.27 CONS Rdest, Rcar, Rcdr

Make a pair to Rdest with Rcar as the first item and Rcdr as the second item.

3.2 Register

3.2.1 MOVE Rdest, Rsource

Move the contents of Rsource to Rdest.

3.2.2 LOAD-IMMED Rdest, index

Load a constant value from index (64bit value and 8bit type) to Rdest. The index is a 24-bit offset to a table of constants within the binary file

3.2.3 LOAD-NULL Rdest

Load a null to Rdest.

3.3 Arithmetic

3.3.1 INT-ADD Rdest, Rfirst, Rsecond

Integer addition of Rfirst, Rsecond to Rdest (Rdest=Rfirst+Rsecond).

3.3.2 INT-SUB Rdest, Rfirst, Rsecond

Integer subtraction of Rfirst, Rsecond to Rdest (Rdest=Rfirst-Rsecond).

3.3.3 INT-MUL Rdest, Rfirst, Rsecond

Integer multiplication of Rfirst, Rsecond to Rdest (Rdest=Rfirst*Rsecond).

3.3.4 INT-DIV Rdest, Rfirst, Rsecond

Integer division of Rfirst, Rsecond to Rdest (Rdest=Rfirst/Rsecond).

3.3.5 INT-MOD Rdest, Rfirst, Rsecond

Integer modulo of Rfirst, Rsecond to Rdest (Rdest=Rfirst%Rsecond). Modulo has the sign of Rsecond.

3.3.6 INT-REM Rdest, Rfirst, Rsecond

Integer remainder of Rfirst, Rsecond to Rdest (Rdest=Rfirst%Rsecond). Remainder has the sign of Rfirst.

3.3.7 FLOAT-ADD Rdest, Rfirst, Rsecond

Float addition of Rfirst, Rsecond to Rdest (Rdest=Rfirst+Rsecond).

3.3.8 FLOAT-SUB Rdest, Rfirst, Rsecond

Float subtraction of Rfirst, Rsecond to Rdest (Rdest=Rfirst-Rsecond).

3.3.9 FLOAT-MUL Rdest, Rfirst, Rsecond

Float multiplication of Rfirst, Rsecond to Rdest (Rdest=Rfirst*Rsecond).

3.3.10 FLOAT-DIV Rdest, Rfirst, Rsecond

Float division of Rfirst, Rsecond to Rdest (Rdest=Rfirst/Rsecond).

3.3.11 FLOAT-MOD Rdest, Rfirst, Rsecond

Float modulo of Rfirst, Rsecond to Rdest (Rdest=Rfirst%Rsecond). Modulo has the sign of Rsecond.

3.3.12 FLOAT-REM Rdest, Rfirst, Rsecond

Float remainder of Rfirst, Rsecond to Rdest (Rdest=Rfirst%Rsecond). Remainder has the sign of Rfirst.

3.3.13 FLOAT-LOG Rdest, Rsource

Computes the natural logarithm of Rsource to Rdest.

3.3.14 FLOAT-LOG10 Rdest, Rsource

Computes the base-10 logarithm of Rsource to Rdest.

3.3.15 FLOAT-EXP Rdest, Rsource

Computes the value of e (the base of natural logarithms) raised to the power of Rsource to Rdest.

3.3.16 FLOAT-SQRT Rdest, Rsource

Computes the square root of Rsource to Rdest.


How about LOG, EXP, (A)SIN, (A)COS, (A)TAN, (trigonometric functions in general)? What happens in case of overflow, underflow, etc?

3.4 Bit level

Bit level operations are valid only for bit strings.

3.4.1 SHR Rdest, Rtarget, Ramount

Shift to right Ramount of bits the value in Rtarget, set the leftmost Ramount bits to zero and put the result to Rdest.

3.4.2 SHL Rdest, Rtarget, Ramount

Shift to left Ramount of bits the value in Rtarget, set the rightmost Ramount bits to zero and put the result to Rdest.

3.4.3 AND Rdest, Rone, Rother

Bitwise AND for values of the same type in Rone and Rother to Rdest.

3.4.4 OR Rdest, Rone, Rother

Bitwise OR for values of the same type in Rone and Rother to Rdest.

3.4.5 XOR Rdest, Rone, Rother

Bitwise XOR for values of the same type in Rone and Rother to Rdest.

3.4.6 NEG Rdest, Rsource

Bitwise negation for the value in Rsource to Rdest.

3.4.7 ROR Rdest, Rtarget, Ramount

Rotate to right Ramount of bits the value in Rtarget and put the result to Rdest.

3.4.8 ROL Rdest, Rtarget, Ramount

Rotate to left Ramount of bits the value in Rtarget and put the result to Rdest.

3.5 Logical

Logical operations are valid only for boolean type.

3.5.1 LAND Rdest, Rone, Rother

Set Rdest to the logical AND of Rone and Rother.

3.5.2 LOR Rdest, Rone, Rother

Set Rdest to the logical OR of Rone and Rother.

3.5.3 NOT Rdest, Rsource

Set Rdest to the logical NOT of Rsource.

3.5.4 BOOLEAN-NOT Rdest, Rsource

Set Rdest to the boolean NOT of Rsource (#f -> #t, #t -> #f, (non-boolean) -> undefined).

3.6 Control

3.6.1 HALT

Stop execution.

3.6.2 JUMP Rtarget

Continue execution from address specified in Rtarget.

3.6.3 JUMPI target

Continue execution from address specified in constant offset target.

3.6.4 BRANCH Rtarget, Rcondition

Continue execution from address specified in Rtarget if Rcondition contains value #f (boolean false).

3.6.5 BRANCHI Rcondition, offset

Continue execution from address specified in offset if Rcondition contains value #f (boolean false).

3.6.6 NOP

Do nothing.

3.7 Stack

The stack pointer is kept in R11. Note that the stack is defined to be a list made out of pairs.
3.7.1 PUSH Rstack, Rsource

Push the contents of Rsource to the stack in Rstack
3.7.2 POP Rstack, Rdest

Remove the topmost element from stack in Rstack and place it to Rdest.

3.7.3 SAVE Rstack, Rbitmask

Push the contents of registers specified in bit string Rbitmask to the stack in Rstack as a vector containing the bit string and the contents of the registers. The first element of the vector contains the bitmap of the saved registers - the rest is implementation specific, and should not be relied upon.

3.7.4 RESTORE Rstack, Rbitmask

Replace the registers specified in bit string Rbitmask from stack in Rstack (stack should contain a vector formed by SAVE - if the bit string contains registers which have not been saved to the vector, they are not replaced).

3.8 Type conversion

3.8.1 INT-TO-FLOAT Rdest, Rsource

Convert the integer value Rsource into a float value in Rdest. If Rsource is not an integer, Rdest is undefined.

3.8.2 FLOAT-TO-INT Rdest, Rsource

Convert the float value in Rsource into an integer value in Rdest. If Rsource is not a float, Rdest is undefined.

3.8.3 INT-TO-BIT-STRING Rdest, Rsource, Rlen

Convert the integer value in Rsource into a bit string in Rdest with length Rlen. If Rsource is not an integer, Rdest is undefined.

3.8.4 BIT-STRING-TO-INT Rdest, Rsource, Rlen

Convert the bit string value in Rsource with length Rlen into an integer value in Rdest. If Rsource is not a bit string, Rdest is undefined.

3.9 Tests

3.9.1 EQ? Rdest, Rone, Rother

Test if the values Rone and Rother are equal (pointer comparison), result to Rdest.

3.9.2 IS-OF-BOOLEAN? Rdest, Rsource

Test if Rsource is of type boolean, result to Rdest.

3.9.3 IS-OF-INTEGER? Rdest, Rsource

Test if Rsource is of type integer, result to Rdest.

3.9.4 IS-OF-FLOAT? Rdest, Rsource

Test if Rsource is of type float, result to Rdest.

3.9.5 IS-OF-PAIR? Rdest, Rsource

Test if Rsource is of type pair, result to Rdest.

3.9.6 IS-OF-PAIR-TAGGED? Rdest, Rsource

Test if Rsource is of type tagged pair, result to Rdest.

3.9.7 IS-OF-VECTOR? Rdest, Rsource

Test if Rsource is of type vector, result to Rdest.

3.9.8 IS-OF-VECTOR-TAGGED? Rdest, Rsource

Test if Rsource is of type tagged vector, result to Rdest.

3.9.9 IS-OF-PRIVATE-BIT-STRING? Rdest, Rsource

Test if Rsource is of type private bit string, result to Rdest.

3.9.10 IS-OF-PRIVATE-BIT-STRING-TAGGED? Rdest, Rsource

Test if Rsource is of type tagged private bit string, result to Rdest.

3.9.11 IS-OF-SHARED-BIT-STRING? Rdest, Rsource

Test if Rsource is of type shared bit string, result to Rdest.

3.9.12 IS-OF-SHARED-BIT-STRING-TAGGED? Rdest, Rsource

Test if Rsource is of type tagged shared bit string, result to Rdest.

3.9.13 IS-OF-PROCEDURE? Rdest, Rsource

Test if Rsource is of type procedure, result to Rdest.

3.9.14 IS-OF-ACTOR-ADDRESS? Rdest, Rsource

Test if Rsource is of type actor address, result to Rdest.

3.9.15 IS-OF-BYTE-CODE? Rdest, Rsource

Test if Rsource is of type byte code, result to Rdest.

3.9.16 INT-CMP Rdest, Rfirst, Rsecond

Integer comparison of Rfirst, Rsecond to Rdest (Rdest=Rfirst == Rsecond).

3.9.17 FLOAT-CMP Rdest, Rfirst, Rsecond

Float comparison of Rfirst, Rsecond to Rdest (Rdest=Rfirst == Rsecond).

3.9.18 INT-GE Rdest, Rfirst, Rsecond

Integer greater-or-equal of Rfirst, Rsecond to Rdest (Rdest=Rfirst >= Rsecond).

3.9.19 FLOAT-GE Rdest, Rfirst, Rsecond

Float greater-or-equal comparison of Rfirst, Rsecond to Rdest (Rdest=Rfirst >= Rsecond).

3.9.20 TAG-CMP Rdest, Rtarget, tag

Test if Rtarget has a tag tag, result to Rdest.

3.10 Bit string

3.10.1 GET-SUBSTRING Rdest, Rsource, Roffset, Rlength

Get substring from Rsource starting from Roffset of size Rlength and store it to Rdest.

Rsource -> 1010101
Rdest   -> 
Roffset -> 2
Rlength -> 3
==> GET-SUBSTRING Rdest, Rsource, Roffset, Rlength ==>
Rsource -> 1010101
Rdest   -> 101
Roffset -> 2
Rlength -> 3

3.10.2 SET-SUBSTRING Rdest, Rsource, Roffset

Set Rsource to be the substring of Rdest starting from Roffset.

Rsource -> 1010101
Rdest   -> 11001100110011
Roffset -> 4
==> SET-SUBSTRING Rdest, Rsource, Roffset ==>
Rsource -> 1010101
Rdest   -> 11001010101
Roffset -> 4

3.11 Special

3.11.1 CREATE-PROCEDURE Rdest, Raddress, Renv

Create a procedure to Rdest with address Raddress and environment Renv.

3.11.2 CREATE-PROCEDURE-IMMEDIATE Rdest, Renv, address

Create a procedure to Rdest with address address and environment Renv.

3.11.3 GET-ADDRESS Rdest, Rprocedure

Put the address of Rprocedure to Rdest.

3.11.4 GET-ENV Rdest, Rprocedure

Put the environment of Rprocedure to Rdest.

3.11.5 SEND-MSG Raddr, Rmsg

Send message Rmsg to Raddr.

3.11.6 SET-EXCEPTION-HANDLER Rsource

Set exception handler to Rsource.

3.11.7 IMM-EXTEND offset

4 Exceptions and messages

4.1 Exception handling

In case of some "abnormal" or asynchronous event occurs, it is called an exception. Exceptions are handled in the exception handler, which can be set to any user defined procedure with SET-EXCEPTION-HANDLER instruction. This procedure should, however, contain the instruction

RESTORE VM_REG_STACK, B1111111111111111
(restores all registers from stack) as the last instruction of the procedure (Actually, if it is not the last already, it will become due to the fact that the VM_REG_PC is restored also). Parameters are passed to the exception handler with the default calling convention. The return value of the exception handler is not used. If the VM_REG_EXCEPTION -register contain NIL, then exceptions are disabled. Whenever there is an exception and the exceptions are disabled, the running agent is terminated (this is a notable fact for exception handler writers). Exceptions are by default disabled before entering the exception handler (the VM_REG_EXCEPTION is set to NIL).

4.2 Exception types

There are several possible exception types and each exception type can have an argument attached. The type of the exception is represented as a bitstring in the exception handler argument. The first phase of the virtual machine handles only messages, exceptions cause the executable to be halted and removed from the system. Here are some of the possible future exceptions described, in addition to the message exception.

4.2.1 MESSAGE

The arrival of a message is an asynchronous event. The natural way to handle these events are therefore exceptions. Exceptions and messages are alike, there is no strict distinction between them. There are some "reserved" names for the system's exceptions, but otherwise there is no noticeable difference.

4.2.2 MATH-OVERFLOW

4.2.3 MATH-UNDERFLOW

4.2.4 MATH-DOMAIN

4.2.5 MATH-RANGE

4.2.6 MATH-DIVZERO

These exceptions are from the arithmetic instructions.

4.2.7 INVALID-ADDRESS

The program counter was set to an invalid value.

4.2.8 INVALID-REFERENCE

Reference to heap invalid; the attempted reference as a parameter.

4.2.9 INVALID-INSTRUCTION

Invalid instruction detected. The bad instruction as a parameter.

5 Types and type tags

Type tags:

HEAP_TYPE_NULL
Null, nil, (whatever you like to call the 'nonexistent')..
HEAP_TYPE_BOOLEAN
Boolean
HEAP_TYPE_INTEGER
64-bit integer
HEAP_TYPE_FLOAT
IEEE double precision floating point number (64-bit)
HEAP_TYPE_VECTOR
Vector
HEAP_TYPE_VECTOR_TAGGED
Tagged vector
HEAP_TYPE_PAIR
Pair
HEAP_TYPE_PAIR_TAGGED
Tagged pair
HEAP_TYPE_SHARED_BSTRING
Shared bitstring
HEAP_TYPE_SHARED_BSTRING_TAGGED
Tagged shared bitstring
HEAP_TYPE_PRIVATE_BSTRING
Private bitstring
HEAP_TYPE_PRIVATE_BSTRING_TAGGED
Tagged private bitstring
HEAP_TYPE_PROCEDURE
Procedure
HEAP_TYPE_ACTOR_ADDR (implemented as 256-bit shared bit string with tag 1, doesn't exist as separate type anymore)
Actor address
HEAP_TYPE_BYTE_CODE (implemented as integer, doesn't exist as separate type anymore)
Byte code

6 Binary representation of instructions

6.1 A proposal

All instructions are 32-bit entities (in big-endian representation), where the highest order byte (bits 24-31) represent the actual instruction number and the following (preceding) bits the parameters for that particular instruction. Each register parameter takes 6 bits and they are ordered just like in their description. Parameters other than registers are defined separately for each command using them. Exception to this scheme are the immediate type instructions, which refer to a constant table in the binary file. 32-bit entity does not provide sufficient amount of bits to address this constant table, so the instruction IMM-EXTEND extends this address space for each immediate type instruction with 24 additional bits, if it precedes it, eg.
IMM-EXTEND 1010 1010 1010 1001 1001 0011
LOADI      r5, 1001 1010 1001 0101 10

=>

LOADI r5, 1010 1010 1010 1001 1001 0011 1001 1010 1001 0101 10

Two consecutive IMM-EXTEND instructions can be provided to extend the indexing capability to full 64bits (first IMM-EXTEND instruction may have few leading obsolete bits depending on how many bits the "real" immediate instruction can provide).

6.1.1 Basic instruction format

6.1.2 Instruction with register operands


© SchemeStation project 1997-1998 [Back to the document index]