Skip to content

vsartor/gvm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Virtual Machine

A simple virtual machine written in Go that started out as a way to pass time during the holidays.

The GVM

The GVM is a very simple virtual machine where you can play with with integer registers, a call stack and a stack.

GBF: GVM Binary File

The GVM executes GVM binary files, which are produced by the compiler.

These are files written with little endian encoding, containing a header used by the GVM to check binary compatibility between itself and the compiled file version. The header is then followed by the number of elements in the code array, followed by the code array itself.

GSM: GVM Assembly Language

The GVM's assembly language is what you use to write code that will be compiled into actual bytecode. The proposed extension is 'gsm', though, of course, this makes no difference.

There are some quality of life simplifications for the written language that make it not an exact map to the GVM compiled bytecode, but all the exceptions are laid out below.

There are a few examples of GSM programs located in the examples folder at the root of this repository. They hopefully can serve as self-explanatory and reasonable examples of GSM usage.

Registers

Integer registers are referred to as r<n> where <n> indicates the number of the register. For example r1 refers to the first integer register and r16 refers to the sixteenth integer register.

Labels

Labels are used to simplify control flow, being essentially an abstraction for the following instruction address.

They are written as tokens ending with :, with the name of the label being everything before the :.

One can also use sublabels. The basic idea is that after any given label lab is defined, any labels starting with a . will be a sublabel of lab, being effectively a short alias for lab.<sublabel> and the sublabel. For example, in the code:

main:
    const r1 2
.second
    const r2 5
    jmp .second

the label .second is effectively an independent label named main.second.

Note that this implies a scope generated by common labels. To illustrate this, consider the example below:

main1:
    const r1 2
.second
    const r2 5
    jmp .second
main2:
    const r1 2
.second
    const r2 5
    jmp .second

which is effectively the same as

main1:
    const r1 2
main1.second
    const r2 5
    jmp main1.second
main2:
    const r1 2
main2.second
    const r2 5
    jmp main2.second

Note also that if a label named main is defined, an instruction is added implicitly by the compiler to the start of the code sequence that jumps to this label, so that it can be used as a logical entry point for the program.

Comments

Comments start with the character ;. As with usual comments, both the character ; and everything that follows it will be ignored by the compiler.

Instructions

Instruction Param Param Description
halt Stops program execution.
const c r Writes the constant c to register r.
push r Pushes the value from register r onto the stack.
pop r Pops the value at the top of the stack into register r.
inc r Increases the value of register r by 1.
dec r Decreases the value of register r by 1.
mov r1 r2 Copies the value of register r1 to register r2.
add r1 r2 Adds the value of register r1 to register r2.
sub r1 r2 Subtracts the value of register r1 from the value of register r2.
mul r1 r2 Multiplies the value of register r1 to the value of register r2
div r1 r2 Divides the value of register r2 by the value of register r1, saving the result in register r2.
rem r1 r2 Stores the remainder of the division of the value of register r2 by the value of register r1 in register r2.
cmp r1 r2 Stores a comparison between registers r1 and r2.
jmp l Jumps to label l.
jeq l Jumps to label l if in last comparison r1 = r2.
jne l Jumps to label l if in last comparison r1 != r2.
jgt l Jumps to label l if in last comparison r1 > r2.
jlt l Jumps to label l if in last comparison r1 < r2.
jge l Jumps to label l if in last comparison r1 >= r2.
jle l Jumps to label l if in last comparison r1 <= r2.
jerr l Jumps to label l if the error flag is set. Empties the error flag.
show r Displays the content of register r to standard output.
call l Jumps to the label l while pushing current position to the callstack.
ret Jumps back to the last position in the callstack popping the value.
noop Does nothing.
iarg r Attempts to interpret the i-th argument as an integer and push to the stack, where i is the value of register r. In case of an error, the error flag is set.

About

Virtual Machine written in Go

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages