Note: this document is still a WIP. Do not read yet unless I told you to!
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 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 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 |
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. |
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.
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