Bytecode
Registers
Prefixed with 'r' there are 16 8-byte registers [ r0, r15 ]
These registers are used to read/write any data to/from.
The addresses for the registers are [0b, 15b]
[128 bytes overhead] * Number of execution contexts (more on that later)
Comments
Everything after a stray ';' on a line will be treated as a comment
Functions
Functions begin with a '<' followed by a name and a ':'. Functions are each given their own operational stack. This allows for the separation of functional memory. Standard function's stack will be emptied upon the return from that function. Every program function can access the following: its own stack, the global stack, and the system registers.
To access a function, a 'call' must occur, you can not jump to a function. Further, you can not jump to a label in another function. Jumping is localized to the function that is currently being operated in.
Pseudo Ops
Directive | Argument | Description |
---|---|---|
.file | "file name" | To help debugging, not required |
.init | entry_label | emit entry_label APP_ENTRY to symbol table |
.string | "string" | emit "string" to global stack |
.int8 | 42 | emit intN to global stack |
.int16 | 42 | emit intN to global stack |
.int32 | 42 | emit intN to global stack |
.int64 | 42 | emit intN to global stack |
.double | 3.14 | emit 3.14 to global stack |
In-place numerical values
For arithmetic operations a drop-in numerical value can be given to an instruction. This drop-in is the numerical value prefixed
with a '$'. These numerical drop-ins are unsigned and encoded directly into the instruction. The valid range for an in-place value
is the maximum number able to be stored by 2 bytes (2^16)
Constants
Upon startup all constants listed will be loaded directly into the global stack. These constants will be loaded in the order by which they
are defined in the file. Ints and doubles that are loaded by const are checked to ensure that they are valid range.
Strings are not limited in size. Ints and doubles will need to be manually checked for sign, as once they're in the VM memory, they are just
bits and bytes.
Note: The size of the global stack is dependant on the constants. It is up to the user to know how to index into the constants.
Instructions
Abbreviations :
Abbreviation | Meaning |
---|---|
r | register |
*n | in-place numerical value |
sp | stack pointer (ls, gs) |
*sp | stack pointer offset ($N(ls), $N(gs)) or rN(ls), rN(gs) for register-based offset |
Note: Stack offsets refer to 'byte' offsets. so $7(gs) is to refer to the 7th byte stored within the global stack
Misc Instructions
Instruction | Arg1 | Arg2 | Arg3 | Description |
---|---|---|---|---|
nop | NA | NA | NA | No Operation |
size | sp | NA | NA | Get size (number of elements) in stack |
Artihmetic Instructions
Instruction | Arg1 | Arg2 | Arg3 | Description |
---|---|---|---|---|
add | r | r , *n | r , *n | Add Arg2 and Arg3, Store in Arg1 |
sub | r | r , *n | r , *n | Sub Arg3 from Arg2, Store in Arg1 |
mul | r | r , *n | r , *n | Mul Arg2 and Arg3, Store in Arg1 |
div | r | r , *n | r , *n | Div Arg2 by Arg3, Store in Arg1 |
add.d | r | r | r | Add (double) Arg2 and Arg3, Store in Arg1 |
sub.d | r | r | r | Sub (double) Arg3 from Arg3, Store in Arg1 |
mul.d | r | r | r | Mul (double) Arg2 and Arg3, Store in Arg1 |
div.d | r | r | r | Div (double) Arg3 by Arg2, Store in Arg1 |
Arithmetic instructions that specify 'd' assumes that the values being operated on are double-precision floating point
numbers, if the value in a given 'd' register is not a floating point, the behavior is undefined.
Bitwise Instructions
Instruction | Arg1 | Arg2 | Arg3 | Description |
---|---|---|---|---|
lsh | r | r , *n | r , *n | Left shift arg 2 by arg3, store in arg 1 |
rsh | r | r , *n | r , *n | Right shift arg2 by arg3, store in arg 1 |
and | r | r , *n | r , *n | And arg 2 with arg 3 store in arg 1 |
or | r | r , *n | r , *n | Or arg 2 with arg 3, store in arg 1 |
xor | r | r , *n | r , *n | Xor arg 2 with arg 3, store in arg 1 |
not | r | r | NA | Flip the bits of arg2 store in arg 1 |
Branch Instructions
Instruction | Arg1 | Arg2 | Arg3 | Description |
---|---|---|---|---|
bgt | r | r | label | Branch to Arg3 if Arg1 > Arg2 |
bgte | r | r | label | Branch to Arg3 if Arg1 >= Arg2 |
blt | r | r | label | Branch to Arg3 if Arg1 <= Arg2 |
blte | r | r | label | Branch to Arg3 if Arg1 <= Arg2 |
beq | r | r | label | Branch to Arg3 if Arg1 == Arg2 |
bne | r | r | label | Branch to Arg3 if Arg1 != Arg2 |
bgt.d | r | r | label | Branch (double) to Arg3 if Arg1 > Arg2 |
bgte.d | r | r | label | Branch (double) to Arg3 if Arg1 >= Arg2 |
blt.d | r | r | label | Branch (double) to Arg3 if Arg1 <= Arg2 |
blte.d | r | r | label | Branch (double) to Arg3 if Arg1 <= Arg2 |
beq.d | r | r | label | Branch (double) to Arg3 if Arg1 == Arg2 |
bne.d | r | r | label | Branch (double) to Arg3 if Arg1 != Arg2 |
Branch instructions assume that the conditional values stored in registers are integer values unless 'd' is specified.
If 'd' is specified and the value in a given register is not a floating point, the behavior is undefined.
Loading / Storing Instructions
Instruction | Arg1 | Arg2 | Description |
---|---|---|---|
mov | r | r, *n | Move data from Arg2 into Arg1 (8-bit max *n) |
ldw | r | *sp | Load word from Arg2 (address) into Arg1 |
stw | *sp | r | Store Arg2 word at Arg1 (arg1=addr) |
ldb | r | *sp | Load data from Arg2 (address) into Arg1 |
stb | *sp | r | Store Arg2 data at Arg1 (arg1=addr) |
push | sp | r | Data from Arg2 into Arg1 |
pop | r | sp | Data from Arg2 into Arg1 |
pushw | sp | r | Word (8 bytes) from Arg2 into Arg1 |
popw | r | sp | Word (8 bytes) from Arg2 into Arg1 |
Jump / Call
Instruction | Arg1 | Description |
---|---|---|
jmp | label | Jump to label |
call | function | Call function - return address stored call stack |
pcall | function | Parallel call - Spawns a new execution context |
ret | Return to the address stored on top of call stack | |
yield | Yield operation of function to caller |
Exit
Instruction | Description |
---|---|
exit | Quit execution of program |
Functions / Labels
Instruction | Description |
---|---|
<funcName: | Create function 'funcName' |
> | End of function declaration |
labelName: | Create label 'labelName' |
Instruction Data
Each full instruction is 8 bytes.
Arithmetic operations
[Byte 1]
The first 6 bits represent the specific instruction (add / mul/ etc)
The remaining 2 bits of the first byte indicate what the remaining bytes represent.
The indication bits are as follows:
00 - Byte 3 will be a register, Byte 4 will be a register
01 - Byte 3 will be a register, Byte 4/5 will be a 2-byte integer
10 - Byte 3/4 will be a 2-byte integer, Byte 5 will be a register
11 - Byte 3/4 will be a 2-byte integer, Byte 5/6 will be a 2-byte integer
[Byte 2]
The second byte is the destination register
Unaccounted bytes will be unused, and marked as '1'
Note: Since drop-ins are not allowed on double-based arithmetic operations, the id bits listed above
and displayed below are not applicable. Instead, double-based arithmetic operations will default to the
'00' case listed below.
Note : Numerical constants are limited to the range of a signed 16-bit integer
Here is an example of the bit layout given an arithmetic operation. Note: All but ID here are filled
with '1' just for the sake of demonstration
Case 00:
INS ID REGISTER REGISTER REGISTER [ ----------------- UNUSED -------------------]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Case 01:
INS ID REGISTER REGISTER [ ---- INTEGER ---- ] [ -------- UNUSED --------------]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Case 10:
INS ID REGISTER [ ---- INTEGER ---- ] REGISTER [ -------- UNUSED --------------]
111111 10 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Case 11:
INS ID REGISTER [ ---- INTEGER ---- ] [ ---- INTEGER ---- ] [ ---- UNUSED ---- ]
111111 11 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Bitwise Operations
[Byte 1]
The first 6 bits represent the specific instruction (add / mul/ etc)
The remaining 2 bits of the first byte indicate what the remaining bytes represent.
The indication bits are as follows:
00 - Byte 3 will be a register, Byte 4 will be a register
01 - Byte 3 will be a register, Byte 4/5 will be a 2-byte integer
10 - Byte 3/4 will be a 2-byte integer, Byte 5 will be a register
11 - Byte 3/4 will be a 2-byte integer, Byte 5/6 will be a 2-byte integer
Note : Numerical constants are limited to the range of a signed 16-bit integer
[Byte 2]
The second byte is the destination register
Unaccounted bytes will be unused, and marked as '1'
Here is an example of the bit layout given a bitwise operation. Note: All but ID here are filled
with '1' just for the sake of demonstration
Case 00:
INS ID REGISTER REGISTER REGISTER [ ----------------- UNUSED -------------------]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Case 01:
INS ID REGISTER REGISTER [ ---- INTEGER ---- ] [ -------- UNUSED --------------]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Case 10:
INS ID REGISTER [ ---- INTEGER ---- ] REGISTER [ -------- UNUSED --------------]
111111 10 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Case 11:
INS ID REGISTER [ ---- INTEGER ---- ] [ ---- INTEGER ---- ] [ ---- UNUSED ---- ]
111111 11 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Branch operations
[Byte 1]
The first 6 bits represent the specific instruction (bge / blt / etc)
The following 2 bits will be set to 00, unused, but also represents that 2 registers are being used.
[Byte 2-3]
The following 2 bytes, are the registers that are used for the branch comparison.
[Byte 4-7]
The following 4 bytes will be the address to branch to.
[Byte 8]
The last byte is unused
Here is an example of a bit layout for a branch operation
INS ID REGISTER REGISTER [ -------------- ADDRESS ----------------] [ UNUSED ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Load / Store operations
mov - Move
Indication Bits:
00 - Register, Register
01 - Register, Numerical Constant - Note : This numerical constant is limited to the range of a signed 32-bit integer.
INS ID REGISTER REGISTER [ ----------------------- UNUSED ---------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
INS ID REGISTER [ --------------- INTEGER ------------------ ] [ ---- UNUSED ----- ]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
stb - Store byte
Indication Bits:
00 - Stack with numerical offset, Source Register
01 - Stack with register-base offset, Source Register
INS ID STACK [ --------------- ADDRESS ---------------] REGISTER UNUSED
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
INS ID STACK REGISTER REGISTER [ ------------------ UNUSED ----------------]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
ldb - Load byte
Indication Bits:
00 - Destination Register, Stack with numerical offset
01 - Destination Register, Stack with register-base offset
INS ID REGISTER STACK [ --------------- ADDRESS ---------------] UNUSED
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
INS ID REGISTER STACK REGISTER [ ------------------ UNUSED ----------------]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
stw - Store word (8 bytes)
Indication Bits:
00 - Stack with numerical offset, Source Register
01 - Stack with register-base offset, Source Register
INS ID STACK [ --------------- ADDRESS ---------------] REGISTER UNUSED
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
INS ID STACK REGISTER REGISTER [ ------------------ UNUSED ----------------]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
ldw - Load word (8 bytes)
Indication Bits:
00 - Destination Register, Stack with numerical offset
01 - Destination Register, Stack with register-base offset
INS ID REGISTER STACK [ --------------- ADDRESS ---------------] UNUSED
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
INS ID REGISTER STACK REGISTER [ ------------------ UNUSED ----------------]
111111 01 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
push - Push
INS ID STACK REGISTER [ ------------------- UNUSED -------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
pop - Pop
INS ID REGISTER STACK [ -------------------- UNUSED ---------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
pushw - Pushw (8 bytes)
INS ID STACK REGISTER [ ------------------- UNUSED -------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
popw - Popw (8 bytes)
INS ID REGISTER STACK [ -------------------- UNUSED ---------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Jump/ call/ pcall/ ret/ yield operations
jmp - Jump
The jump operation is straight forward. The only data in the jump is the address to jump to.
INS ID [ --------------- ADDRESS --------------- ] [ ---------- UNUSED ----------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
call - Call
Upon executing the call instruction, the address immediately after call's address will be stored in
the system stack.
INS ID [ --------------- ADDRESS --------------- ] [ ---------- UNUSED ----------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
pcall - pcall
Upon executing the pcall instruction, the destination address will be sent to the virtual machine to
have a new context spawned at that address location. The VM will stay alive until all contexts are completed.
The context will be completed once the new context's call stack is empty and instructions from the destination
address are completed.
INS ID [ --------------- ADDRESS --------------- ] [ ---------- UNUSED ----------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
ret - Return
The return address will be on the top of the system stack. Executing return will return to whatever
address is on the top of the system stack, and then pop it.
INS ID [ ----------------------------------- UNUSED ----------------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Note: Implicit returns happen at the bottom of a function. If the bottom of the function is reached,
a return will occur.
yield - Yield
Yields execution back to caller. Upon detecting yeild, the function's instruction pointer and local
stack is preserved and the caller continues execution as if a return occured. Upon the next call into
the function that has yielded, execution will continue from the instruction immediately following the
yeild. Multiple yeilds can me made, and if the bottom of the function occurs, or if a ret is executed
the function will be reset.
INS ID [ ----------------------------------- UNUSED ----------------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Misc Instructions
Nop
INS ID [ -------------------------------------- UNUSED ---------------------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Size
INS ID REGISTER STACK [ ---------------------------- UNUSED -------------------------------]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Constants
Constant creation instructions don't follow standard instruction layout which is why they were saved for last.
.int
id bits: 00 - 8-bit int [1 byte following ins byte]
id bits: 01 - 16-bit int [2 bytes following ins byte]
id bits: 10 - 32-bit int [4 bytes following ins byte]
id bits: 11 - 64-bit int [8 bytes following ins byte]
INS ID [ --- INTEGER BYTES ---- ]
111111 00 | 1111 1111 .... | 1111 1111
.string
id bits ignored
The current maximum is 255 bytes for a string
INS ID SIZE [ ------- STR BYTES ------ ]
111111 00 | 1111 1111 | 1111 1111 | .... | 1111 1111
.double
id bits ignored, size is 9 bytes fixed
INS ID [ -------------------------------------- DOUBLE DATA -------------------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
The stack
In this system, there are multiple stacks, but only 2 that can be accessed at any given time programatically. The local stack, and the global stack.
Local stack
A stack accessed by 'ls' for 'local stack' that accesses the stack preserved for the current function. Once the system leaves the function, the local stack is blown away.
Global stack
A stack accessed by 'gs' for 'global stack' that accesses the stack used across the entire program. Great care should be taken when using this stack, as there is no garbage collection in the scope of what I care to do here.
Call stack
Not able to be accessed by software directly. The system stack is pushed and popped by calls and returns.
Forbidden Instructions
There are instructions that exist that are required by the system that the user does not need to worry about, but they need to be
documented for the sake of the implementation.
function start - Currently allows 2^48 instructions per function
Function start / end are special instructions that are scanned for upon initial program load
to tell the VM how to structure its self.
INS ID [ --------------------- NUM INSTRUCTIONS IN FUNC ------------------------------ ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
function end
INS ID [ ---------------------------------- UNUSED ----------------------------------- ]
111111 00 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
callstack_store_function
Tell the system to put a function address in the call stack
INS [ --------------- ADDRESS --------------- ] [ ---------- UNUSED ----------- ]
11111111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
callstack_store_roi
Tell the system to put a function location in the call stack
INS [ --------------- ADDRESS --------------- ] [ ---------- UNUSED ----------- ]
11111111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
These instructions are used in the back-end to make calls and returns work. When a call is written by a user, these are generated
by the byte gen to tell the system to put the function and region the call came from such-that returns can identify where to go to
begin_constant_segment
Tell the system that the following area is the binary is constants
INS [ ---------------------------------- Number of constants ---------------------------------- ]
11111111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
begin_function_segment
Tell the system that the following are is functions.
INS [ ---------------------------------- Entry Function Address ------------------------------- ]
11111111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
binary_end
Right now the data is unused, but eventually the unused section will contain a binary checksum
INS [ ----------------------------------- Unused ---------------------------------- ]
11111111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
Assembly Code
Functions
All instructions must be placed in a function. When a function is accessed it has an empty 'local stack' that can only be used by that function. When the function is exited (by hitting end of function, or 'ret'), the local stack is freed.
.file "Some file name info"
.init main
; The 'init' function - Where the VM will start off
<main:
; Instructions for the function go here.
; When a function is accessed, its local stack is created and of size '0'
; Call the function 'example' Functions can be define in whatever order,
; as long as they get defined if solace is being used to compile the byte code
call example
; While not required, ret should be used for efficiency sake. More steps are required to attempt
; returning if not explicitly told to return
ret
>
<example:
; Example now has its own local stack to operate with, and can access the global stack / registers
ret
>
Constants
Constants in ASM are predefined values to be loaded into the program's global stack in the order that they are defined.
Not all constants are shown here. Check out the Nable Byte Code document to see all of the constant directives.
.double pi 3.14159 ; A double.
.int64 answer 42 ; An 8-byte integer.
.string myStr "This is an example of a string."
.init main
<main:
ret
>
Loading and storing
; Anywhere that 'ls' is seen, 'gs' can be placed to work with the global stack instead of the local stack.
.init main
<main:
mov r9 $45 ; Put the number '45' into register 9
mov r7 r9 ; Put value of r9 into r7
pushw ls r9 ; Push the value from r9 into the local stack
size r0 ls ; Get the number of frames in the local stack and store it in r0 (Should be 1 at this time)
popw r10 ls ; Pop the new value into a new register
pushw ls r9 ; Put r9 back into the local stack
; The next two instructions need to be done with care. If the stacks are indexed out of bounds, a fault will occur
ldb r0 $0(ls) ; Load the value placed in without popping
stw $0(ls) r9 ; Place the value of a register into a stack.
; In addition to using $N(ls), the stacks can be indexed by a register value for stw and ldw.
mov r0 $1
ldw r1 r0(ls) ; Loads local stack value at the index of the value in r0 (1)
stw r0(ls) r9 ; The same thing works with stw
ret
>
Jumping Around
.init main
; Jumping can only occur within a function. You can not jump to labels in other functions
; Labels jumped to can be before or after the jmp instruction
<main:
jmp first
second: ; Labels look a lot like function declarations, but they aren't instructions at all.
jmp last ; when solace runs over the .asm file, they are turned into addresses for placement
; inside the jmp instruction
first:
jmp second
last:
ret
>
Branching
; There are a lot of branches, so we aren't showing them all here. No way.
; Branches branch to labels, and can only branch within their function.
; To branch based of registers containing doubles, the branch '.d' variant must be used,
; otherwise weird 'undefined' things can happen
.init main
<main:
mov r0 $0 ; Put 0 into reg 0
mov r1 $5 ; Put 5 into reg 1
testLabel:
add r0 r0 $1 ; inc r0 by 1
blt r0 r1 testLabel ; while r0 < r1
ret
>
Getting out
.init main
<awesome:
exit ; The moment exit is found, the vm bails out. No further processing will occur
>
<moreso:
ret
>
<main:
call awesome
call moreso ; This won't happen at all
ret
>
The meat and potatoes - Math
; For every arithmetic operation listed, there is a '.d' variant for
; doing that same operation on doubles. Note: .d operations don'e allow
; numerical drop-ins (things prefixed with a '$'
.init math
<math:
mov r0 $2
mul r0 r0 $2 ; Multiply 2 by 2 and store in r0
add r0 r0 r0 ; Add 4 to 4 and store in r0
sub r0 r0 $2 ; Subtract 2 from 4 store in r0
div r0 $10 r0 ; Divide 10 by 2 and store in r0
>