This is a small virtual machine that executes a custom-made machine language using Javascript. The web application includes an HTML5 console, which can be used to interact with programs. The web application also includes a text field into which custom programs can be entered, and then executed. Code must be entered as a series of hex bytes separated by spaces and new lines.
Registers are slots in which 2 bytes of data can be stored. These slots are identified by a 1-byte index number. The first 4 multi-purpose registers are numbered from 1-4, and can hold two bytes of data. The next 8 slots, numbered 5-12, are the lower and higher portions of the 2-byte registers. For example, register 6 is the higher portion of register 1, and register 7 is the lower portion of register 2. Register 0 is the flags register. Registers may sometimes be referred to with the notation reg(n)
, where n is the register number.
The flags register is a 2-byte integer register that holds CPU related information. All flags are a single bit. These flags are as follows, ordered from least to most significant bit:
- CF - set when an add operation overflows
- DF - set by comparators, 1 is greater than, 0 is less than or equal
- EF - set by comparator if the operands are equal => DF=0
65536 bytes of memory are provided for the programs execution. However, the highest 1922 bytes of this memory are reserved for graphics memory. The program itself is loaded at the address 0x0, yielding a maximum program size of 63614 bytes.
In the following list, arguments are separated by commas. Here are the kinds of arguments that you will see:
@arg - a two-byte memory address <arg> - a two-byte raw value {arg} - a single-byte register index
Instruction | Arguments | Number | Description |
no-op | () | 0x0 | does nothing |
set | ({a}, <b>) | 0x1 | moves `b` into `a` |
regcopy | ({a}, {b}) | 0x2 | sets `a` to `b` |
read | ({a}, @b) | 0x3 | reads one or two bytes from `b` into `a` |
write | (@a, {b}) | 0x4 | writes the contents of `b` into `a` |
xor | ({a}, {b}) | 0x5 | sets `a` to `a` ^ `b` |
and | ({a}, {b}) | 0x6 | sets `a` to `a` & `b` |
or | ({a}, {b}) | 0x7 | sets `a` to `a` | `b` |
add | ({a}, {b}) | 0x8 | adds the number stored in `b` to the value of `a` |
sub | ({a}, {b}) | 0x9 | sets `a` to `a` - `b` |
div | ({a}, {b}) | 0xA | sets `a` to `a` / `b`; sets `reg(4)` to the modulus |
mul | ({a}, {b}) | 0xB | 0xB, sets `a` to `a` * `b` |
compare | ({a}, {b}) | 0xC | compares `a` to `b`, DF is 1 if `a` > `b` |
ljump | ({a}) | 0xD | jumps to the address stored in `a` |
ajump | (@a) | 0xE | jumps to the pre-defined address `a` |
jge | (@a) | 0xF | jumps to `a` if DF is 1 and EF is 0 |
jle | (@a) | 0x10 | jumps to `a` if DF is 0 and EF is 0 |
je | (@a) | 0x11 | jumps to `a` if EF is 1 |
bell | () | 0x12 | rings a bell |
({a}) | 0x13 | prints an ASCII character to the video memory | |
readch | ({a}) | 0x14 | reads an ASCII character from the keyboard |
hlt | () | 0x15 | shuts down the system |
readreg | ({a}, {b}) | 0x16 | writes the value at the address stored in `b` to `a` |
writereg | ({a}, {b}) | 0x17 | writes `b` to the address stored in `a` |
Here is a sample program that prints "type here:" and then echoes the user's key presses. Note that the # indicates a comment, and that this is not currently supported by the web app. In the event that you wish to test this code, you must remove all text after and including each #.
01 07 01 00 # increment counter in reg(7)
01 01 24 00 # buffer address in reg(1)
16 09 01 # read char into reg(9)
13 09 # print reg(9)
08 01 07 # add reg(7) to reg(1)
01 08 35 00 # set reg(8) to end of buffer
0C 01 08 # compare reg(1) and reg(8)
11 1D 00 # if they are equal, jump to code
0E 08 00 # otherwise, go back and do another character
# address: 0x1D
14 05 # read key to reg(5)
13 05 # print reg(5)
0E 1D 00 # jump to code
# address: 0x24
74 79 70 65 20 68 65 72 65 3A
# address: 0x35