Nano VM

The Nano virtual machine has a 64 bit core with lots of registers.

Similar projects worth following
Programs for Nano VM can be written in Assembly or N a high level language inspired by C, BASIC and my own ideas. Nano VM runs currently on Linux, Android and Windows. Programs using graphics/GUI and sound are possible with the Flow server program.

Flow also can access the serial port (RS232) on Linux and Windows. Flow communicates via TCP/IP with the Nano VM. So both programs can be runned on the same machine or on different machines.

I started this project about 2002, I got the idea to create my own virtual machine.
I didn't know at this moment how challenging the whole project would become.

Now the VM has even a JIT-compiler using AsmJit library to do just in time compilation of some opcodes. The VM can also load shared libraries and can access the stack of the VM and the array variables from a library.

The project is open source dual licensed under the GPL/MPL.

Here is a simple "Hello world!" written in my N language:

func main ()
    int n = 1; int ret = 0; int x;

    print "Hello world!";
    printn n;

    x = 2 * 2 << 2; x = ++;
    print x;
    printn n;

    exit ret;

The math expression is calculated from left to right. And x = ++; would be x++; in C. Here is the assembly output of the N compiler:


lab main;
    int n@main;
    push_i 1, L0;
    pull_i L0, n@main;
    int ret@main;
    push_i 0, L1;
    pull_i L1, ret@main;
    int x@main;
    push_s "Hello world!", S0;
    print_s S0;
    print_n L0;
    push_i 2, L2;
    mul_l L2, L2, L2;
    smul_l L2, L2, L2;
    pull_i L2, x@main;
    inc_l L2;
    pull_i L2, x@main;
    print_l L2;
    print_n L0;
    exit L1;
The first line ston; switches the stack on. It's the function call stack. The push opcodes "push" constants or variables into registers. A pull opcode "pulls" register content into variables. In this example every variable of the function main gets the @main tacked on, to mark them as the main function variables.

The next example shows a simple for loop:

func main ()
    int x; int f; int max = 10; int null = 0; int one = 1;


    x = 1;
        print "Hello world!";
        printn one;

        x = ++;
        f = x <= max;
    next f;

    exit null;

The index range check is done by "f = x <= max;". The next checks if the expression in f is true, as long as it's true the loop continues.

If we take a look at the assembly code generated by the N compiler. Then we see that the generated code (-O2 optimization on) looks like this:


lab main;
    int x@main;
    int f@main;
    int max@main;
    push_i 10, L0;
    pull_i L0, max@main;
    int null@main;
    push_i 0, L1;
    pull_i L1, null@main;
    int one@main;
    push_i 1, L2;
    pull_i L2, one@main;
    push_i 1, L3;
    pull_i L3, x@main;

lab for_0;
    push_s "Hello world!", S0;
    print_s S0;
    print_n L2;
    inc_lseq_jmp_l L3, L0, for_0;
    exit L1;

The three for loop control lines are now a simple "inc_lseq_jmp_l L3, L5, for_0;". The L3 register is the "x" counter variable and the L0 register the "max" variable. So one opcode makes the work of three.

  • I2C library for Raspberry Pi

    jay-t06/12/2017 at 15:54 0 comments

    I wrote a I2C library for the Raspberry Pi. It's done via WiringPi library.

    I wrote an example how to read out a MPU 6050 accellerometer + gyro. So this would be a good start to learn how to use my I2C library.

    The new source code is available on my Nano VM GitHub repo.

    Here is the short example program:

    //	i2clib.nanoc
    //	reads i2c port with shared library
    //	Stefan Pietzonke 2017
    func main ()
    	lint null = 0; lint one = 1;
    	qint _fd = 0;
    	lint _dll;
    	lint _setup;
    	lint _writereg8;
    	lint _readreg8;
    	string dllname[256] = "";
    	string i2csetup[256] = "i2c_setup";
    	string i2cwritereg8[256] = "i2c_writereg8";
    	string i2creadreg8[256] = "i2c_readreg8";
    	int gyroskop_xout;
    	int gyroskop_yout;
    	int gyroskop_zout;
    	int accel_xout;
    	int accel_yout;
    	int accel_zout;
    //	open library in nanovm/lib directory
    	lopen (_dll, dllname);	
    //	set function handles
    	lfunc (_dll, _setup, i2csetup);
    	lfunc (_dll, _writereg8, i2cwritereg8);
    	lfunc (_dll, _readreg8, i2creadreg8);
    //	init module MPU 6050
    	pushtostack (&68);
    	lcall (_dll, _setup);
    	get (_fd, >);
    //	print "_fd: ", _fd; printn one;
    //	setup MPU 6050
    	pushtostack> (_fd, &6B, 0);
    	lcall (_dll, _writereg8);
    	@read_word_2c (_fd, &43);
    	get (gyroskop_xout);
    	@read_word_2c (_fd, &45);
    	get (gyroskop_yout);
    	@read_word_2c (_fd, &47);
    	get (gyroskop_zout);
    	@read_word_2c (_fd, &3B);
    	get (accel_xout);
    	@read_word_2c (_fd, &3D);
    	get (accel_yout);
    	@read_word_2c (_fd, &3F);
    	get (accel_zout);
    	print "gyroskop"; printn one;
    	print "x: ", gyroskop_xout; printn one;
    	print "y: ", gyroskop_yout; printn one;
    	print "z: ", gyroskop_zout; printn one;
    	printn one;
    	print "accelleration"; printn one;
    	print "x: ", accel_xout; printn one;
    	print "y: ", accel_yout; printn one;
    	print "z: ", accel_zout; printn one;
    	printn one;
    	printn one;
    	exit null;
    func read_word_i2c (qint fd, int reg)
    	int h;
    	int l;
    	int value;
    //	print "fd: ", fd; printn 1;
    	pushtostack (reg, fd);
    	lcall (_dll, _readreg8);
    	get (h, >);
    	reg = ++;
    	pushtostack (reg, fd);
    	lcall (_dll, _readreg8);
    	get (l, >);
    	value = h << 8 + l;
    	return (value);
    func read_word_2c (qint fd, int reg)
    	int val;
    	int f;
    	int ret;
    	@read_word_i2c (fd, reg);
    	get (val);
    	f = val >= &8000;
    	if f;
    		ret = 65535 - val + 1;
    		ret = 0 - ret;
    		ret = val;
    	return (ret);
    lab pushtostack;

  • Portable Version on GitHub

    jay-t02/05/2016 at 06:22 0 comments

    I released a portable version of my Nano VM on GitHub. Nano can now be copied on a USB stick and run from there. There is no installation required.

    The binaries for Linux and Windows are in the bin directory. On Linux there are shell scripts which run the VM. This was needed because there is no Linux "execute" permission on a FAT32 file system. There is a README file in the archive.

    Nano VM portable version

    The archive is at the bottom. The README file in the archive is in English. There are binaries for Android also in the archive.

View all 2 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates