Quadmachine 2

Introduction

Quadmachine is a virtual instruction set architecture, designed mainly for educational purposes. It has the following noteworthy features:

All of these, except for the preposterously large register file, are realistic for a 64-bit RISC design. The size of the register file is intended to trivialize register allocation in expository compilers.

This package is a software realization of the Quadmachine architecture. It is written in Java for portability; speed was not an implementation concern.

Here are some sample Quadmachine assembly programs:

The latest version is 2.4.0, released on 2007-02-10. Download the software at http://antti-juhani.kaijanaho.fi/software/dist/. Bleeding edge sources are available via darcs by the command darcs get http://antti-juhani.kaijanaho.fi/darcs/quadmachine/.

The class fi.jyu.mit.quadmachine.VirtualMachine is the façade to the implementation. It can be invoked as the main class, or it can be directly instantiated by another Java program.

This is the second design and implementation of Quadmachine, both by Antti-Juhani Kaijanaho in December 2006. The first design was done in August 2004 by Antti-Juhani Kaijanaho and implemented by Tuukka Hastrup. The main changes are the introduction of general-purpose registers, the increase of word and address size from 32 to 64 bits, and move from a memory-memory instruction set to a load-store instruction set.

Instruction set

There are two interfaces to the instruction set in the implementation: the assembler and the InstructionSet Java interface.

In assembly, register operands are denoted by $N, where N is an unsigned base-10 number between 0 and 65535, inclusive. All other numeric literals are also in base-10 (although, confusingly, disassembly uses base-16). Mnemonics are case-insensitive, labels are case-sensitive.

Registers $0 to $65533 (inclusive) are general purpose. The register $65534 can be used like a general purpose register, but it is customarily reserved for use as the stack pointer. The register $65535 is always zero and ignores any write attempts.

Unless otherwise indicated, the first operand is where the result is stored.

Assembly instructionInstructionSet methodDescription
Load instructions
ld $N, $M addIntegers copies the content of $M to $N. Note that this is just another name for add $N, $M, $65535.
ld $N, imm loadImmediate copies the integer imm to $N.
ld $N, label loadLabel copies the address denoted by label to $N.
ld $N, [M] loadDirect copies the word at address M to $N.
ld $N, [label] loadDirectLabel copies the word at address denoted by label to $N.
ld $N, [$M+K]
ld $N, [$M-K]
loadIndirect copies to $N the word at the address obtainable by adding (or subtracting) K to (from) the content of $M.
Store instructions
st $N, [M] storeDirect copies the content of $N to the word at address M.
st $N, [label] storeDirectLabel copies the content of $N to the word at address denoted by label.
st $N, [$M+K]
st $N, [$M-K]
storeIndirect copies the contet of $N to the word at the address obtainable by adding (or subtracting) K to (from) the content of $M.
Integer arithmetic
add $N, $M, imm addImmediate Adds together integers. The third operand, imm, is an immediate integer. Note that it does not matter whether the integers are signed or unsigned; the operation is identical for both types.
add $N, $M, $K addIntegers Adds together integers. Note that it does not matter whether the integers are signed or unsigned; the operation is identical for both types.
sub $N, $M, $K subtractIntegers Subtracts the content of $K from the content of $M. Note that it does not matter whether the integers are signed or unsigned; the operation is identical for both types.
muls $N, $M, $K, $L multiplyIntegers Multiplies the 64-bit signed integers stored in $K and $L, and stores the resulting 128-bit signed integer in $N (the least significant 64 bits) and $M (the most significant 64 bits).
mulu $N, $M, $K, $L multiplyUnsigned Multiplies the 64-bit unsigned integers stored in $K and $L, and stores the resulting 128-bit unsigned integer in $N (the least significant 64 bits) and $M (the most significant 64 bits).
divs $N, $M, $J, $K, $L divideIntegers Divides the 128-bit signed integer stored in $J (most significant 64 bits) and $K (least significant 64 bits) by the 64-bit signed integer $L, and stores the results as follows: the quotient in $N and the remainder in $M.
divu $N, $M, $J, $K, $L divideUnsigned Divides the 128-bit unsigned integer stored in $J (most significant 64 bits) and $K (least significant 64 bits) by the 64-bit unsigned integer $L, and stores the results as follows: the quotient in $N and the remainder in $M.
Bitwise operations
shl $N, $M, $K shiftLogically Shifts $M to the left bitwise by $K bits. If $K is negative, the shift is to the right by the absolute value of $K. New bits are initialized to zero.
sha $N, $M, $K shiftArithmetically Shifts $M to the left bitwise by $K bits. If $K is negative, the shift is to the right by the absolute value of $K. New rightmost bits are initialized to zero; the leftmost bit is copied to any new leftmost bits, thereby performing sign extension.
and $N, $M, $K binaryAnd Performs the bitwise AND operation.
not $N, $M binaryNot Performs the bitwise NOT operation.
or $N, $M, $K binaryInclusiveOr Performs the bitwise (inclusive) OR operation.
xor $N, $M, $K binaryExclusiveOr Performs the bitwise XOR (exclusive or) operation.
Jumps and branches
jump label jump Jumps (unconditionally) to the address denoted by label.
jump [$N] jumpIndirect Jumps (unconditionally) to the address stored in the register $N.
jz $N, label jumpIfZero Jumps to the address denoted by label, if $N is zero.
jn $N, label jumpIfNegative Jumps to the address denoted by label, if $N is negative.
jp $N, label jumpIfPositive Jumps to the address denoted by label, if $N is zero.
jnz $N, label jumpUnlessZero Jumps to the address denoted by label, unless $N is zero.
jnn $N, label jumpUnlessNegative Jumps to the address denoted by label, unless $N is negative.
jnp $N, label jumpUnlessPositive Jumps to the address denoted by label, unless $N is zero.
System calls
sys read invokeSystem(SYS_READ)

System call to read from a file.

Parameters

  • $0 contains a nonnegative signed integer, a token referring to an open file. The file tokens 0, 1 and 2 are open at startup and refer to the standard input, standard output and standard error, respectively.
  • $1 contains an address that indicates the start of the buffer where the data is read to.
  • $2 contains a signed nonnegative integer that represents the length of the buffer in octets.

Return values

  • $0 contains a signed integer that specifies the number of octets read. This value, when positive, can be smaller, but not larger, than the length of the buffer, even if there is no error and even if the end of the file is not reached. If the length of the buffer was nonzero and this return value is zero, then the end of the file was reached. If this value is negative, an error occurred.

Failure conditions

  • If the file was not opened for reading, this system call will fail.
  • Any I/O error may result in a short read (that is, the number of octets read will be less than the length of the buffer). Any subsequent invocations of this system call will, in any case, indicate failure for this file.
sys write invokeSystem(SYS_WRITE)

System call to write to a file.

Parameters

  • $0 contains a nonnegative signed integer, a token referring to an open file. The file tokens 0, 1 and 2 are open at startup and refer to the standard input, standard output and standard error, respectively.
  • $1 contains an address that indicates the start of the buffer where the data is written from.
  • $2 contains an unsigned integer that represents the length of the buffer in octets.

Return values

  • $0 contains a signed integer that specifies the number of octets written. This value, when nonnegative, can be smaller, but not larger, than the length of the buffer, even if there is no error. If this value is negative, an error occurred.

Failure conditions

  • If the file was not opened for writing, this system call will fail.
  • Any I/O error may result in a short write (that is, the number of octets written will be less than the length of the buffer). Any subsequent invocations of this system call will, in any case, indicate failure for this file.
sys exit invokeSystem(SYS_EXIT)

System call to terminate the program.

Parameters

  • $0 contains an unsigned integer. Zero value is used to indicate successful termination, others indicate failure of some unspecified kind.

Return values

The system call does not return.

Failure conditions

The system call does not fail.

Miscellaneous
slide imm slideRegisters

Slides the register window up (if positive) or down (if negative). More precisely:

If imm is positive, the following happen:

  1. $65534 is decremented by 8*imm.
  2. The registers between $0 (inclusive) and $imm (exclusive) are stored in the memory area [sp]..[sp+8*imm], where sp refers to $65534.
  3. Except for $65534 and $65535, each $N is renamed $M, where M is the remainder of N-imm divided by 65534.

If imm is negative, the following happen:

  1. Except for $65534 and $65535, each $N is renamed $M, where M is the remainder of N-imm divided by 65534.
  2. The registers between $0 (inclusive) and $-imm (exclusive) are loaded from the memory area [sp]..[sp-8*imm], where sp refers to $65534.
  3. $65534 is decremented by 8*imm.

If imm is zero, this instruction merely makes sure that the segment in which the current address stored in $65534 lies is mapped in.


2007-02-10 Antti-Juhani Kaijanaho <antti-juhani@kaijanaho.fi>

Valid XHTML 1.0 Strict