TomVM User Manual

Note: this document is still a WIP. Do not read yet unless I told you to!

Features

Instructions

Opname Usage Restrictions Description
IMM IMM R, i 0 <= i <= 4095 Set reigster R to immediate value i
ADDIMM ADDIMM R, i 0 <= i <= 127 Add unsigned immediate value i to register R
ADDIMMS ADDIMMS R, i -64 <= i <= 63 Add unsigned immediate value i to register R
ADD ADD TGT, A, B Add values in registers A and B, store result in register TGT
SUB SUB TGT, A, B Subtract values in registers B from register A, store result in register TGT
MUL MUL TGT, A, B Multiply values in registers A and B, store result in register TGT
AND AND TGT, A, B Perform logical AND on values in registers A and B, store result in register TGT
OR OR TGT, A, B Perform logical OR on values in registers A and B, store result in register TGT
XOR XOR TGT, A, B Perform logical XOR on values in registers A and B, store result in register TGT
MOD MOD TGT, A, B Calculate the value in register A modulo the value in register B, store result in register TGT
SHIFTL SHIFTL TGT, R, i 0 <= i <= 15 Shift the value in register R left by i bits, store result in register TGT
SHIFTRG SHIFTRG TGT, R, i 0 <= i <= 15 Shift the value in register R right by i bits, store result in register TGT
SHIFTRA SHIFTRA TGT, R, i 0 <= i <= 15 Shift the value in register R right by i bits, store result in register TGT. if the high bit of register R is set, then it is sign extended.
LOADWORD LOADWORD TGT, A, M Load a word from memory at the 32-bit address taken by combining the value of registers A and M, where M is treated as bits 31-16 and A is treated as bits 15-0. Store result in register TGT
STOREWORD STOREWORD V, A, M Store the value of register V in memory at the 32-bit address taken by combining the value of registers A and M, where M is treated as bits 31-16 and A is treated as bits 15-0
LOADBYTE LOADBYTE TGT, A, M Load a byte from memory at the 32-bit address taken by combining the value of registers A and M, where M is treated as bits 31-16 and A is treated as bits 15-0. Store result in register TGT. This always sets the upper 8-bits of register TGT to zero.
STOREBYTE STOREBYTE V, A, M Store the lower 8-bits of the value of register V in memory at the 32-bit address taken by combining the value of registers A and M, where M is treated as bits 31-16 and A is treated as bits 15-0
TEST TEST A, B, T Perform a testop T on the values of registers A and B. If the testop passes, set the TEST flag to 1. See TestOps for a list of all valid testops.
ADDIF ADDIF A, B, i 0 <= i <= 15 If the TEST flag is set, then A = B+i and unset the TEST flag.
STACK STACK A, SP, OP Perform a stackop on a stack located at the address in SP, with an argument in, or destination of, reigster A
LOADSTACK LOADSTACK A, SP, i 0 <= i <= 15 Load a word from a stack located in memory at SP, i places from the top.
JUMP JUMP i i = 0 or 16 <= i <= 16284 Set the program counter to i. The value stored in i is in the range [0, 1024], and is left shifted by 4.
JUMPR JUMPR A, M Set the program counter to the 32-bit address created by combining the value of registers A and M, where M is treated as bits 31-16, and A is treated as bits 15-0.
BRANCH BRANCH i 0 <= i <= 1023 Set the program counter to PC+i
BRANCHIF BRANCHIF i 0 <= i <= 1023 If the TEST flag is set, set the program counter to PC+i and unset the TEST flag.
BRANCHIFR BRANCHIFR A If the TEST flag is set, set the program counter to PC+ the value of register A and unset the TEST flag.
SYSTEM SYSTEM Zero, A, i 0 <= i <= 15 Call the system signal index i, with A as the argument. This signal can perform any action, modifying memory and changing registers.
SYSTEM SYSTEM S, _, i 0 <= i <= 15 Call the system signal index S, with i as the argument. This signal can perform any action, modifying memory and changing registers.

TestOps

TestOps perform a comparison between two registers. The result of a TestOp is used to set the TEST flag of the processor. If the condition is true then the flag is set, otherwise it is unset. Every TEST instruction operates on 2 register operands, in this table referred to as A and B.

Name Condition
Eq A == B
Neq A != B
Lt A < B
Lte A <= B
Gt A > B
Gte A >= B
BothZero A == B && A == 0
EitherNonZero A != 0 || B != 0
BothNonZero A != 0 && B != 0

StackOps

StackOps are the stack manipulation operations that the STACK instruction performs. Each stackop operates on 2 registers, which are operands of the STACK instruction. In the instruction STACK TGT SP OP these register values represent the target of the operation, and the SP or "stack pointer" - this is the the address the machine's memory where the stack operation is performed. This means that multiple stacks can be operated on, and their values can reside in any general purpose register. This machine does not use a dedicated register for the value of the stack pointer, however by convention the register R5 is used as the stack pointer, and it is given the name SP in the assembler.

StackOp Action
Pop SP -= 2; TGT = MEM[SP]
Push MEM[SP] = TGT; SP += 2
Peep TGT = MEM[SP-2]
Swap tmp = MEM[SP-2]; MEM[SP-2] = MEM[SP-4]; MEP[SP-4] = tmp
Dup MEM[SP] = MEM[SP-2]; SP += 2
Rot tmp = MEM[SP-2]; MEM[SP-2] = MEM[SP-4]; MEM[SP-4] = MEM[SP-6]; MEM[SP-6] = tmp
Add MEM[SP-4] = MEM[SP-2] + MEM[SP-4]; SP -= 2
Sub MEM[SP-4] = MEM[SP-4] - MEM[SP-2]; SP -= 2
PushPC MEM[SP] = PC; SP += 2

System Signals

The SIGNAL instruction raises a signal that must be handled by the system. These signals can interface with hardware that is not exposed through regular instructions. This table is the set of default signals that the VM will respond to, however hardware devices can define new signal handlers. See the documentation of each hardware device for the signals that it defines.

Note: only HALT (0xF) is currently implemented

ID Name Arg Description
0x1 INTERRUPT interrupt value Trigger a user interrupt, jump to the interrupt handler vector, indexed by the interrupt value
0x2 SET INTERRUPT ENABLED true/false If arg is 1, enable user interrupts. Otherwise, disable user interrupts
0xA SET FAULT HANDLER address When a system fault occurs, setup a fault context and jump to the handler address.
0xB SET INT VECTOR address When a system interrupt is triggered, setup a interrupt context and jump to the handler address.
0xF HALT (ignored) Set the HALT status of the system to true. This ends execution.

Assembler Syntax

The program TVM-ASM assembles programs for the machine, and outputs files in the SBF format.

Instructions are written in the form INSTRUCTION A B C, without commas between the operands. For example, this program reads 2 bytes from a serial input device mapped to address 0xE001, and sums them.

IMM D $E00
# D = $E001, but we can only load 12-bit immediates
SHIFTL D D 4
ADDIMM D 1
LOADBYTE A D Zero
LOADBYTE B D Zero
ADD A A B
    

The assembler also has support for variables, labels, and a basic macro system.

Labels and Variables

A label is like a bookmark in the assembly code. When a label is encountered, the assembler calculates the offset of this label in the final program, and other places can reference this offset. A label is defined using the : character, with a name for the label. In this example, we branch to a label and skip over loading 20 into the A register. When this program halts, A = 10.

IMM A 10
BRANCH !SKIP
IMM A 20
:SKIP
SYSTEM Zero Zero $f
      

To reference a label, we use its name with the ! prefix. This applies to labels, as well as any variables that are defined. Variables are defined by using the defvar macro. In this example, we define a variable for the HALT signal handler index.

.defvar SIG_HALT $f
IMM A 10
SYSTEM Zero Zero !SIG_HALT
      

Binary Format

This machine defines its own binary format, SBF (simple binary format) for loading programs and data. These files follow a simple specification one main header followed by section headers, the finally the data referenced by each section header.

Binary Header

The main header contains the following fields, in order:

Section Header

The section headers immediately follow the main binary header. Each section header defines data that will loaded into memory, or some information for the loader to configure memory. The total size of the section headers is 12 bytes × section count. Each section header contains the following fields, in order:

Section Modes

Each section has a mode which determines how it is handled by the loader.