The instruction format is designed to be simple for the virtual machine to decode and for a user to read. It is not like a real machine code format in that it is human-readable bytes of text. As a result, though, the machine code format looks much like assembly code.
Note that this instruction format is also not as extensive as a real instruction set would be. For example, only integer manipulation is directly supported -- no floating point numbers.
Although it is simple, this instruction set is sufficient to perform significant computations. Therefore, it will allow us to create short- and long-lived processes that are performing actual computation. This page documents the instruction set, including the registers that can be used as well as the interrupts and interrupt handling mechanisms.
Below are listed the registers available for this machine.
Below are listed all of the traps that the virtual machine may generate, and that the kernel may receive. Along with each trap, we provide the offset into the trap table (that is, the trap table entry number) for that trap. In that trap table entry must be a pointer to the kernel trap handler function for that type of trap. We also list, for each trap, the values placed into the system registers (%s0 - %s3) before execution is vectored into the kernel.
The processor will normally advance the PC to the next instruction after executing the current instruction. However, there are some circumstances under which the PC is not advanced. These are the exceptions:
An invalid instruction interrupt occurs. These are raised when an opcode cannot be decoded, or when the operands provided are not valid.
An invalid memory access interrupt occurs. If an instruction fetch, load, or store attempts to use an invalid address, this interrupt is generated.
A successful branch or jump occurs. When such an instruction succeeds in setting the PC to a new value, that new PC value is not incremented.
In all other circumstances the PC is advanced. Note that the setting of the PC by the kernel does not form an exception to its normal advancement.
Each instruction is exactly 32 bytes, irrespective of the instruction used. The simple multiplication of two constants, in machine code format, would look something like this:
STRI 00000005 103ef200 00000000 STRI 0000001c 00000004 00000000 MULR 0000000b 00000005 0000001c
More generally, notice the common characteristics of every instruction:
This exact format must be followed. If it is not, then the decoding component of the virtual machine will likely get confused, and complain that some part of the code contains an illegal instruction, an illegal address, or an invalid register number.
(Note that, technically, the space characters between the opcode and operands could be any character, including, say, a tab character. There must be *some* character, though, that the decoder can skip before examining the next piece.)
Below is a catalog of instructions and their associated interpretation of the operands that follow. Specifically, in each description, we will refer to the opcode, as well as operand-0, operand-1, and operand-2.
This instruction generates an intention interrupt that forces the processor to trap into the kernel. It is the method by which a program can perform an unusual kind of procedure call, where the procedure is inside the kernel and the arguments are passed in the system registers.
All three operands are unused by this instruction. However, the setting of the system registers are the means of communication to the kernel. The convention for how these registers are used are determine by the kernel itself, which may define how values are passed into and returned from the system call.
Copy a value from one register into another. Set register operand-0 to hold the value contained in register operand-1.
Copy an immediate value into a register. Set register operand-0 to hold the immediate value operand-1.
Copy a value from a main memory location into a register. The main memory address is computed by adding register operand-1 to immediate operand-2. The value at this address is copied into register operand-0. Note that the address must be a word-aligned location.
Copy a value from a register into a main memory location. The main memory address is computed by adding register operand-1 to immediate operand-2. The value in register operand-0 is copied into this address. Note that the address must be a word-aligned location.
Add register operand-1 to register operand-2 and store the result in register operand-0.
Add register operand-1 to immediate operand-2 and store the result in register operand-0.
Subtract register operand-2 from register operand-1 and store the result in register operand-0.
Subtract register operand-2 from immediate operand-1 and store the result in register operand-0.
Multiply register operand-1 with register operand-2 and store the result in register operand-0.
Multiply register operand-1 with immediate operand-2 and store the result in register operand-0.
Divide register operand-1 by register operand-2 and store the result in register operand-0.
Divide register operand-1 by immediate operand-2 and store the result in register operand-0.
Bitwise AND register operand-1 with register operand-2 and store the result in register operand-0.
Bitwise AND register operand-1 with immediate operand-2 and store the result in register operand-0.
Bitwise OR register operand-1 with register operand-2 and store the result in register operand-0. The trailing underscore (_) is critical to ensure a four-byte opcode.
Bitwise OR register operand-1 with immediate operand-2 and store the result in register operand-0. The trailing underscore (_) is critical to ensure a four-byte opcode.
Bitwise NOT register operand-1 and store the result in register operand-0.
Bitwise NOT immediate operand-1 and store the result in register operand-0.
Shift register opcode-1 by the number of bits specified in immediate opcode-2, and store the result in register opcode-0. Note that bits with the value 0 are inserted into the word from the right end.
Shift register opcode-1 by the number of bits specified in immediate opcode-2, and store the result in register opcode-0. Note that bits with the value 0 are inserted into the word from the left end.
Jump to the address in register opcode-0. This instruction causes the virtual machine to set the program counter to the new address in the executable.
Jump to the address in immediate opcode-0. This instruction causes the virtual machine to set the program counter to the new address in the executable.
If register opcode-1 is equal to register opcode-2, jump to the address in immediate opcode-0.
If register opcode-1 is not equal to register opcode-2, jump to the address in immediate opcode-0.
If register opcode-1 is greater than register opcode-2, jump to the address in immediate opcode-0.
If register opcode-1 is less than register opcode-2, jump to the address in immediate opcode-0.
If register opcode-1 is greater than or equal to register opcode-2, jump to the address in immediate opcode-0.
If register opcode-1 is less than or equal to register opcode-2, jump to the address in immediate opcode-0.
Jump to the address in immediate opcode-0. Before jumping, store PC + 32 (that is, the address of the next instruction) into the return address register (%ra).