[ Back ]
When you compile a NaaLaa program, all your code is converted into simple instructions that the NaaLaa virtual machine (VM) can interpret. When Marcus was working on the Raycasting library, he realized that the compiler wasn't always that smart. Yes, he thought that he, the almighty one, could make a better job himself (which is funny, as he was the one who wrote the compiler in the first place). He therefore made some of the VM instructions available for himself and all other NaaLaa programmers.
Almost every instruction consists of a command, a destination and a source. The destination is usually a register or a variable. The source is often a register, a variable or a constant. You already know what variables and constants are. Registers can be used as temporary variables. There are "a couple" of registers, and you can use five of them without worries. They're referred to as @0 .. @4. The registers are a little faster than variables (especially variables in arrays and local variables ... and references to local array elements).
There's a command named MOV, that moves a value from one place to another. So let's say you wanted to swap the values of two variables, an_int and another_int. You'd probably write:
tmp = an_int
an_int = another_int
another_int = tmp
But this generates a whole bunch of instructions. With the MOV instruction you could use a register as a temporary variable and write:
MOV @0 an_int
MOV an_int another_int
MOV another_int @0
, which is a lot faster.
Besides from the registers, there's also a stack that can be used as temporary storage. You can push values from variables, registers and constants to this stack, and you can pop values from the stack to variables and registers. You do so with the PSH and POP commands.
Many commands let you operate on array elements. However, you can not use the arrays directly. First you need to load an array into a register. What you actually load is a pointer to the first element of the array. You load an array to a register with the normal MOV command. You can then use a command named STP to move forward one or more elements in the array. To set or access the variable that a pointer points at you use square brackets around the register identifier. Ex:
rem Create an array.
my_array = [1, 2, 3, 4]
rem Load array into register 0.
MOV @0 my_array
rem Step to last element of array.
STP @0 3
rem Change the value of the element to 42.
MOV [@0] 42
There are no loops or selection statements when you work with VM instructions. Instead you do unconditional and conditional jumps to labels. With the CMP command, you can compare a value (variable, register ...) with another value. This command sets a piece of information somewhere that you can use to do a conditional jump. There are many types of jump commands. JLE, for example, does a jump to the specified label only if the first value passed to the CMP command was less than or equal to the second value. You create a label with the @ character followed by a name and a colon. In this example we go through a loop 1000 times:
rem Use register 0 as a counter, set it to 1.
MOV @0 1
rem Our loop label.
rem Increase counter by 1.
ADD @0 1
rem Compare counter with 1000.
CMP @0 1000
rem Jump to my_loop if counter is less than or equal to 1000.
Most of the commands listed below work with floating points aswell. A register can store a floating point value, and with some tweaking you can put floats on the stack aswell. To use floating point values you have to add a # character to the command. It will work on most commands but not on all (seriously, the Creator isn't quite sure about the commands that wont work with floating point values, so you'll simply have to test). Here's an example of a loop, like the one above, but with a floating point counter:
MOV# @0 1.0
ADD# @0 0.5
CMP# @0 1000.0
MOV dst src
ADD dst src
SUB dst src
MUL dst src
DIV dst src
MOD dst src
CMP dst, src
Move value of src to dst.
Step with src in array reg.
Add src to dst.
Subtract src from dst.
Mutiply dst with src.
Divide dst with src.
Let dst become dst mod src.
Push value of src to stack.
Pop value from stack to dst.
Compare dst with src.
Jump to label.
Jump to label if dst was equal to src in last CMP.
Jump to label if dst was not equal to src in last CMP.
Jump to label if dst was greater than src in last CMP.
Jump to label if dst was greater than or equal to src in last CMP.
Jump to label if dst was less than src in last CMP.
Jump to label if dst was less than or equal to src in last CMP.
Convert integer value in register reg to float.
Convert float value in register reg to integer.
[ Back ]