The Basics

The nano virtual machine is register based. The're 32 registers for long int
and 32 registers for double numbers. The math opcodes use the registers.
So a variable or constant has to be pushed into a register before a operation.

To do this we need the "push" opcode:

    push_i  10, L0;
    
Pushes the constant "10" into register "L0".

To write a register to a variable, we need the "pull" opcode:

    pull_i  L0, x;
    
Pulls register "L0" into the short int variable "x".

Lets see this in an example. We want to calculate "77 * 88" and store
the result in variable "x". The line numbers are for reference only, they are
not a part of the program.

        calc_1.na

     1| int x;
     2|
     3| push_i  77, L0;
     4| push_i  88, L1;
     5| mul_l   L0, L1, L2;
     6| pull_i  L2, x;
     7|
     8| push_i  0, L4;
     9| exit    L4;
    
The first line declares the variable "x" as "int".

In line 5 we do the multiplication: "L2 = L0 * L1". Note the "L" before
a register means "long int". So we need the "mul_l" opcode there.

Line 9 exits the program and sets a return value for the shell environment.
We set "0", so it means no error.

Note: NEVER FORGET THE "exit" OPCODE!
THIS IS IMPORTANT!
You also have to take care that the program flow reaches the "exit" opcode!


This example has some drawback, we can't see the result. We need to print it
on the screen. Here comes the "print" opcode into play:

    print_l	L2;
    
As you can see, it's simple to use. Only the right register is needed.
But we want to print a "new line" after the result, to get a formatted output:

    push_i	1, L3;
    print_n	L3;
    
The "print_n" opcode prints the number of newlines as set in the register.
Here's the new program:

        calc_2.na

     1| int x;
     2|
     3| push_i  77, L0;
     4| push_i  88, L1;
     5| mul_l   L0, L1, L2;
     6| pull_i  L2, x;
     7|
     8| print_l L2;
     9| push_i	1, L3;
    10| print_n L3;
    11|
    12| push_i  0, L4;
    13| exit    L4;
    

Opcodes

    L = long register, D = double register
    BV = byte variable, IV = int variable, LV = long int variable
    DV = double variable, SV = string variable
    V = variable, N = integer variable
    
    {} = optional (arrays)
    

variable declaration

    byte            BV{[NV]};
    int             IV{[NV]};
    lint            LV{[NV]};
    double          DV{[NV]};
    string          SV[NV];
    

variable, constant to register

    push_b          BV, L;
    push_i          IV, L;
    push_l          LV, L;
    push_d          DV, D;
    

register to variable

    pull_b          L, BV;
    pull_i          L, IV;
    pull_l          L, LV;
    pull_d          D, DV;
    

register to register

    move_l          L1, L2;         L1 to L2
    move_d          D1, D2;         D1 to D2
    
Next: Console Input