From 9c8c3f87397e4379e3ea996e6a154711dd22a1f1 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Sun, 20 Aug 2023 21:51:31 +0100 Subject: [PATCH] Publish a post about vm arrays and functions --- .../note.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 content/posts/vm_progress_update_arrays_and_function_calls/note.md diff --git a/content/posts/vm_progress_update_arrays_and_function_calls/note.md b/content/posts/vm_progress_update_arrays_and_function_calls/note.md new file mode 100644 index 0000000..b777166 --- /dev/null +++ b/content/posts/vm_progress_update_arrays_and_function_calls/note.md @@ -0,0 +1,119 @@ +X-Date: 2023-08-20T21:40:00Z +X-Note-Id: 906d96de-189c-4755-89b9-3cd43f6e9542 +Subject: VM progress update: arrays and function calls +X-Slug: vm_progress_update_arrays_and_function_calls + +The virtual machine I'm working on can now allocate and access arrays from the bytecode and assembly. +Arrays are one of the basic data structures in the VM, in addition to numeric types and pointers. +Until now, I was only able to operate with arrays from unit tests, because memory allocation and garbage +collection wasn't fully there. + +Now, with garbage collection and memory allocation in place, the following is possible: + +``` +;; Allocate an array of 10240 untyped +;; elements and place a pointer to it +;; into register r1 +arri r1, 10240 + +;; Load '42' into register r2 +li r2, 42 + +;; Put the content of r2 into the array +;; pointed to by r1 with offset of 10000 +asi r1, r2, 10000 + +;; Read the content of the array with +;; offset of 10000 to register r0 +ali r0, r1, 10000 +``` + +When saved as `array.asm`, you can byte-compile it and execute like this: + +``` +$ cat array.asm | ./asm | ./vm +R0: 42 +``` + +As of now, R0 is printed by default when the virtual machine executes the last +instruction. + +Another interesting feature that is available now is "jump-and-link". It is based on the same +concept in the RISC-V architecture, pretty much like x86 "call". It jumps to a specific offset +and stores the address of the next instruction in the specified register. Here's an example: + +``` +begin: + ;; Load '42' into register r2 + li r2, 42 + + ;; Jump to label 'fun' and store + ;; the address of next instruction in + ;; the r3 register + jal r3, fun + + ;; Continue execution after return from + ;; 'fun' + ;; Increment register r0 + addi r0, r0, 1 + + ;; Jump to label 'end' unconditionally + jmp end + +fun: + ;; Copy content of register r2 into + ;; register r0 + mov r0, r2 + + ;; Jump to location saved in r3 + jr r3 + +end: + ;; End of program +``` + + +And there are now also stack operation. They look and work pretty much like you would expect +on normal hardware, except that the stack is also accessible as an array. + +``` +;; Load '42' into register r2 +li r2, 42 + +;; Load '43' into register r3 +li r3, 43 + +;; Push register r2 onto the stack +push r2 + +;; Update the stack's top element +;; to be the content of register r3. +;; The 'sp' is a register that contains +;; stack pointer. Negative offsets +;; are supported as well. +asi sp, r3, 0 + +;; Pop the top element of the stack +;; into register r0 +pop r0 +``` + +For the stack, I also have a "base pointer" which is supposed to serve as an address of the +current call frame. It would be useful when the time comes to compile an actual language into +the bytecode. + +In addition to the new instructions, the virtual machine now loads the bundle of both code and +data from the binary representation. Data section is needed for storing larger constant objects +that I would need when implementing the programming language on top of it. For example, 64-bit +integers, floating point constants, strings and others. The assembly compiler though currently +just emits empty data section because it can't properly evaluate constants yet. This would be +something I'll handle separately. + +All in all, I'm quite happy with the progress. The code is a bit messy and ugly, but it is slowly +making it into a better state as I add more functionality and do refactoring bit-by-bit. + +After ironing out the basics, I would probably work on the dynamic linking and interaction with +a C FFI. This is needed to give the code executing in the virtual machine ability to call +external functions (like filesystem access, network and others). + +As usual, the experimental code can be found [here](https://git.sr.ht/~knazarov/lisp.experimental).