Files
rasp/vm.md
2020-01-28 18:35:41 -05:00

205 lines
4.4 KiB
Markdown

# VM
This is an outline of the VM that drives this language.
# Primitives
* Numbers may be big endian (BE) or little endian (LE) at the byte level. This guide will use LE.
* Addresses point to single bytes.
* Signed numbers use two's complement.
| Type | Size (bits) |
| - | - |
| Address | 64 |
| Word | 64 |
| Halfword | 32 |
| Byte | 8 |
# Registers
CPU registers are addressed by a value between 0-63 (6 bits). All registers are 64 bits wide.
* IP - Instruction pointer
* SP - Stack pointer
* FP - Frame pointer
* FLAGS - CPU flags
* (9 unused registers)
* STATUS - Generic status code
* R0-R49
## CPU Flags
CPU flags are addressed by bit index, going from right to left.
* `00` - Halt flag
* `01` - Compare flag
### Flag ideas
* "Trace" flag - halts the CPU when certain conditions are met that may be causing undesired
behavior - for debugging
* Overwriting a register without its value being used
* Mixing arithmetic with bit twiddling on the same target
## Register ideas
* NULL - a register that will always be zero for reading and will not change after writing.
* Other possible names: Z, NIL
# Instructions
## Arithmetic
Arithmetic instructions store their result in the first register specified. Overflow is handled by
wrapping around to 0.
* Add
* **Params**: REG1, REG2
* `REG1 = REG1 + REG2`
* Unsigned addition
* Mul
* **Params**: REG1, REG2
* `REG1 = REG1 * REG2`
* Unsigned multiplication
* Div
* **Params**: REG1, REG2
* `REG1 = REG1 / REG2`
* Unsigned division
* Mod
* **Params**: REG1, REG2
* `REG1 = REG1 % REG2` (exact semantics TBD)
* INeg
* **Params**: REG1
* `REG1 = REG1 * -1`
* Signed negative
* And
* **Params**: REG1, REG2
* `REG1 = REG1 & REG2`
* Or
* **Params**: REG1, REG2
* `REG1 = REG1 | REG2`
* Inv
* **Params**: REG1
* `REG1 = ~REG1`
* Not
* **Params**: REG1
* ```
if REG1 == 0 {
REG1 = 0;
} else {
REG1 = 1;
}
```
* Boolean NOT; equivalent of C's `!` unary operator
* Xor
* **Params**: REG1, REG2
* `REG1 = REG1 ^ REG2`
* Shl
* **Params**: REG1, REG2
* `REG1 = REG1 << REG2`
* Shr
* **Params**: REG1, REG2
* `REG1 = REG1 >> REG2`
* Does not sign extend
### TODO
* Add signed instructions (iadd, imul, etc)
* Sign-extending SHR
* Overflow flag?
## Control flow
* CmpEq
* **Params**: REG1, REG2
* ```
if REG1 == REG2 {
FLAGS[1] = 1;
} else {
FLAGS[1] = 0;
}
```
* Sets the COMPARE flag to 1 if REG1 == REG2
* CmpLt
* **Params**: REG1, REG2
* ```
if REG1 < REG2 {
FLAGS[1] = 1;
} else {
FLAGS[1] = 0;
}
```
* Sets the COMPARE flag to 1 if REG1 < REG2
* Jz
* **Params**: REG1
* ```
if FLAGS[1] == 0 {
IP = REG1;
}
```
* Jumps to the address in REG1 if COMPARE flag is 0.
* Jnz
* **Params**: REG1
* ```
if FLAGS[1] != 0 {
IP = REG1;
}
```
* Jumps to the address in REG1 if COMPARE flag is 1.
## Data movement
* Load
* **Params**: REG1, REG2
* ```
REG1 = MEM[REG2];
```
* Sets REG1 to the value at the memory address in REG2.
* Store
* **Params**: REG1, REG2
* ```
MEM[REG2] = REG1;
```
* Sets the value at the memory address in REG2 to the value in REG1.
* StoreImm32
* **Params**: REG1, IMM_32
* `REG1 = IMM_32`
* Sets REG1 to the specified 32-bit number.
* MemCopy
* **Params**: REG1, REG2
* `MEM[REG1] = MEM[REG2]`
* Copies the value at the memory address in REG2 to the memory address in REG1.
* RegCopy
* **Params**: REG1, REG2
* `REG1 = REG2`
* Copies the value in REG2 into REG1.
## Miscellaneous
* Halt
* **Params**: (none)
* `FLAGS[0] = 1`
* Halts the machine
* Nop
* **Params**: (none)
* Does nothing
## Other instructions TODO
* Call
* Takes address and number of bytes on the stack that are for args(?)
* Updates SP, FP, IP, storing previous values starting at the new FP
* Ret
* Uses FP to determine previous SP, FP, and IP and restores them
* Push
* Pop
* More immediate stores?
# General TODO
* Interrupts
* MMIO regions
* Execution pipeline
* Helps to define when certain side effects happen (e.g. when the IP increments)
* Paging?