This repository has been archived on 2025-11-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
aal/README.org
Aryadev Chavali e6effcf654 Added steps to creating an in memory instance of the VM
This would be useful when writing an interpreted language where the
"assembly" and the "execution" occur within the same executable.
2023-11-03 22:14:24 +00:00

89 lines
3.5 KiB
Org Mode

#+title: Oreo's Virtual Machine (OVM)
#+author: Aryadev Chavali
#+date: 2023-10-15
A stack based virtual machine in C11, with a dynamic register setup
which acts as variable space. Deals primarily in bytes, doesn't make
assertions about typing and is very simple to target.
* How to build
Requires =GNU make= and a compliant C11 compiler. Code base has been
tested against =gcc= and =clang=, but given how the project has been
written without use of GNU'isms (that I'm aware of) it shouldn't be an
issue to compile using something like =tcc= or another compiler (look
at [[file:Makefile::CC=gcc][here]] to change the compiler).
To build everything simply run ~make~. This will build:
+ [[file:lib/inst.c][instruction bytecode system]] which provides
object files to target the VM
+ [[file:vm/main.c][VM executable]] which executes bytecode
+ [[file:asm/main.c][Assembler executable]] which assembles compliant
assembly code to VM bytecode
+ [[file:examples/][Assembly examples]] which provide some source code
examples on common programs one may write. Use this to figure out
how to write compliant assembly. Also a good test of both the VM
and assembler.
You may also build each component individually through the
corresponding recipe:
+ ~make lib~
+ ~make vm~
+ ~make asm~
+ ~make examples~
* Instructions to target the virtual machine
You need to link with the object files for
[[file:lib/base.c][base.c]], [[file:lib/darr.c][darr.c]] and
[[file:lib/inst.c][inst.c]] to be able to properly target the OVM.
The basic idea is to create some instructions via ~inst_t~,
instantiating a ~prog_t~ structure which wraps those instructions
(includes a header and other useful things for the runtime), then
using ~prog_write_file~ to serialise and write bytecode to a file
pointer.
To execute directly compiled bytecode use the ~ovm.out~ executable on
the bytecode file.
For clarity, one may build ~lib~ (~make lib~) then use the resulting
object files to link and create bytecode for the virtual machine.
** In memory virtual machine
Instead of serialising and writing bytecode to a file, one may instead
serialise bytecode in memory using ~prog_write_bytecode~ which writes
bytecode to a dynamic byte buffer, so called *in memory compilation*.
To execute this bytecode, deserialise the bytecode into a program then
load it into a complete ~vm_t~ structure (linking with
[[file:vm/runtime.c][runtime.c]]).
In fact, you may skip the process of serialising entirely. You can
emit a ~prog_t~ structure corresponding to source code, load it
directly into the ~vm_t~ structure, then execute. To do so is a bit
involved, so I recommend looking at [[file:vm/main.c]]. In rough
steps:
+ Create a virtual machine "from scratch" (load the necessary
components (the stack, heap and call stack) by hand)
+ Load program into VM (~vm_load_program~)
+ Run ~vm_execute_all~
This is recommended if writing an interpreted language such as a Lisp,
where on demand execution of code is more suitable.
* Lines of code
#+begin_src sh :results table :exports results
find -name '*.[ch]' -exec wc -l '{}' ';'
#+end_src
#+RESULTS:
| 301 | ./vm/runtime.h |
| 92 | ./vm/main.c |
| 1059 | ./vm/runtime.c |
| 500 | ./lib/inst.c |
| 39 | ./lib/darr.h |
| 265 | ./lib/inst.h |
| 42 | ./lib/heap.h |
| 90 | ./lib/base.h |
| 101 | ./lib/heap.c |
| 39 | ./lib/base.c |
| 77 | ./lib/darr.c |
| 654 | ./asm/parser.c |
| 142 | ./asm/main.c |
| 83 | ./asm/lexer.h |
| 65 | ./asm/parser.h |
| 549 | ./asm/lexer.c |