A virtual machine library with an assembler and a compiler for a B-like programming language. Written in TypeScript and transpiled into Luau with roblox-ts.
NOTE: Not yet complete.
- CPU
- RAM
- ROM
- I/O ports
- Peripherals (not implemented)
- GPU
- Permanent storage (not implemented)
Everything is in 64-bits, henceforth called memory units or just units for short.
For full descriptions, check ./src/shared/vm.shared.ts.
64-bit double registers, 32-bit instruction set.
- Instruction Pointer (IP)
- Stack Pointer (SP)
- Flags (FS, 32 bits due to Luau limitations)
- General purpose (RA ~ RM)
256 64-bit double ports numbered 0x00 ~ 0xFF
00: Motherboard 01: Keyboard 02: Mouse 03: Permanent storage
NOTE: Not really implemented yet.
IEEE 754 64-bit doubles are used for everything, but bitwise operations are limited to 32-bits according to Luau behaviour.
The programmer can tell the CPU to regularly call a function every so-and-so units of time. This acts as an analogy to interrupts in real CPUs, with the scall and dcall instructions.
Stack grows from the top of memory. The ROM sets up the stack.
[0x00000000] 0xAAAABBBB
- The bits in [] is unusable for instructions.
- The bits in A compose the instruction proper, containing information about the arguments (whether internal or external) to the instruction in the higher eight bits, and the opcode in the lower eight bits.
- The bits in B compose the internal (within the same memory unit) arguments, should they exist.
The return value is stored in the RA register. The other registers that must be preserved by the callee are RJ ~ RM, inclusive.
Arguments are pushed on the stack, where the first argument is pushed first. The arguments themselves do not have to be preserved (i.e. the callee can use them as scratch).
The number of arguments passed to a function should be set in the RA register by the caller.
Each memory unit is a 64-bit double or number in Luau.
Must be between 0x000000 ~ 0x0FFFFF inclusive.
| Addr.ess | Information |
|---|---|
| 0x000000 ~ 0x000FFF | ROM |
| 0x001000 ~ 0x002FFF | VMEM |
| 0x003000 ~ 0x0FFFFF | General-purpose RAM |
The GPU only supports text, and can have an abitrary dimensions as long as the area is less than 0x1800.
NOTE: Not fully implemented.
0x [00000000] ABCDEEEE
- The bits in [] are unuseable due to Luau behaviour
- Red is in A
- Blue is in B
- Green is in C
- Alpha is in D
- 16-bit Unicode code point is in E
Intel syntax. Here's an example program. (Haven't tested it BTW.)
_start:
// push a register offset to skip the next instruction once the function returns
push ip @+ 2;
// yes there is no call instruction
mov ip, main;
hlt;
main:
pushc; // pushes RJ ~ RM
mov ra, [variable]; // returns 53
popc; // pops RM ~ RJ
ret;
variable: data 53;Here's an example of the B-like syntax. This calculates the nth number in the Fibonacci sequence.
/* Fibonacci sequence calculator, translated from C. */
// inline assembler
[[
mov sp, 0xFFFFF; // set up the stack
]];
fib(n) {
var f_old = 0;
var f_1 = 1;
var f_n = 0;
while (n != 0) {
f_old = f_n;
f_n = f_n + f_1;
f_1 = f_old;
n = n - 1;
}
return f_n;
}
main() {
return fib(200);
}MIT License. Check LICENSE if you want to read it.
Shout out to Plasmism for having made something like this a few months earlier and a million times better! I've only recently learned about his project while developing this. :') Oh well
Check his project out here: https://plasmism.dev/blog/how-i-built-rovm
Shout out also to Bisqwit for having made his creating a compiler playlist which I watched a few years ago. It's also why I'm making my language B-like as well.
Check his playlist here: https://www.youtube.com/playlist?list=PLzLzYGEbdY5n9ITKUqOuRjXkRU5tMW2Sd
Soli Deo Gloria!