65.9K
CodeProject is changing. Read more.
Home

A basic Virtual Machine for Experimentation

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.10/5 (40 votes)

May 14, 2003

viewsIcon

70780

A basic Virtual Machine for experimentation.

Introduction

A rather QAD mini VM, for experimentation.

using System;
using System.Collections;

public class MiniVM {

   public static void Main(string [] args) {
    AVM vm = new AVM();

    String srcCode = "";
    srcCode += "           loadr 1 1;";
    srcCode += "loop:      cmpt  1 5 exit;";
    srcCode += "           sysPrint msg;";
    srcCode += "           incr  1 1;";
    srcCode += "           jump  loop;";
    srcCode += "exit:      brk;";
    srcCode += "msg:       data.string 'Hello World';";

    vm.asmCode(srcCode);

    vm.execCode();

   }
}

public class AVM {
    private byte []     vmc         = new byte[128];
    private Hashtable     lookupReplace     = new Hashtable();

    public void loadCode(byte [] newcode) {
        for ( int i = 0 ; i < newcode.Length ; i++ )
            vmc[i] = newcode[i];
    }

    private String [] getParms(String cLine) {
        String []     xparms     = cLine.Split(new char []{' '});
        String []     yparms     = new String[xparms.Length];
        int         parmCnt = 0;
        
        for ( int j = 0 ; j < xparms.Length ; j++ ) { // All this crap because String.Split includes extra tokens.
            if ( xparms[j] != String.Empty )
                yparms[parmCnt++] = xparms[j];
        }
        String [] parms = new String[parmCnt];
        Array.Copy(yparms, parms, parmCnt);

        return parms;
    }
    
    private int lookup(String sVal, int pc) {
        int v = -1;
        
        try { 
            v = Int16.Parse(sVal);
        } catch ( Exception e ) {
        }
        if ( v == -1 ) 
            lookupReplace.Add(pc, sVal);

        return v;
    }

    public void asmCode(String src) {
        String [] srcL = src.Split(new char [] {';'});
        asmCode(srcL);
    }
    
    public void asmCode(String [] src) {
        int pc = 0;
        Hashtable labels = new Hashtable();

        for ( int i = 0 ; i < src.Length ; i++ ) {
            if  ( src[i] == String.Empty ) continue;
            
            String         cLine     = src[i];
            String []     parms     = getParms(cLine);
            int         cmdPos     = 0;
            
            if ( parms[cmdPos].EndsWith(":") ) {
                labels.Add(parms[cmdPos].Substring(0, parms[cmdPos].Length-1), pc);
                cmdPos++;
            }
            
            switch ( parms[cmdPos] ) {
                case "sysPrint":
                    vmc[pc++] = 1;
                    int v = lookup(parms[cmdPos+1], pc);
                    vmc[pc++] = (byte)v;
                    break;
                case "brk":
                    vmc[pc++] = 0;
                    break;
                case "loadr":
                    vmc[pc++] = 2;
                    vmc[pc++] = (byte)(lookup(parms[cmdPos+1], pc));
                    vmc[pc++] = (byte)(lookup(parms[cmdPos+2], pc));
                    break;
                case "cmpt":
                    vmc[pc++] = 3;
                    vmc[pc] = (byte)(lookup(parms[cmdPos+1], pc));
                    pc++;
                    vmc[pc] = (byte)(lookup(parms[cmdPos+2], pc));
                    pc++;
                    vmc[pc] = (byte)(lookup(parms[cmdPos+3], pc));
                    pc++;
                    break;
                case "incr":
                    vmc[pc++] = 4;
                    vmc[pc++] = (byte)(lookup(parms[cmdPos+1], pc));
                    vmc[pc++] = (byte)(lookup(parms[cmdPos+2], pc));
                    break;
                case "jump":
                    vmc[pc++] = 5;
                    vmc[pc] = (byte)(lookup(parms[cmdPos+1], pc));
                    pc++;
                    break;
                case "data.string":
                    String x = cLine.Substring(cLine.IndexOf("data.string")+12);
                    //Console.WriteLine("LIT:"+x);
                    char [] c = x.ToCharArray();
                    for ( int j = 1 ; j < c.Length-1 ; j++ ) {
                        vmc[pc++] = (byte)(c[j]    );
                    }
                    vmc[pc++] = 0;
                    break;
            }
        }

        IDictionaryEnumerator myEnumerator = lookupReplace.GetEnumerator();
        while ( myEnumerator.MoveNext() ) {
             int val = (int)(labels[myEnumerator.Value]);
                 //Console.WriteLine("Sub {0} {1}", myEnumerator.Key, myEnumerator.Value+ " ="+val);
             vmc[(int)(myEnumerator.Key)] = (byte)val;
        }   

        //for ( int i = 0 ; i < pc ; i++ )
        //    Console.WriteLine(i+"::"+vmc[i]);
    }

    public void execCode() {
        int     pc     = 0;
        int     ilc     = 1;
        bool     cont     = true;
        int []     regs     = new int[16];
        
        while ( cont ) {
            byte currInst = vmc[pc];
            //Console.WriteLine(pc+":"+currInst+ "  ,  " + vmc[pc+1] + "  , " + vmc[pc+2]+ "  , " + vmc[pc+3]);
            switch ( currInst ) {
                case 0 : // brk
                    cont = false;
                    break;
                case 1 : // sysPrint
                    String p = "";
                    for ( int i = 0 ; vmc[vmc[pc+1]+i] != 0 ; i++ )
                        p += (char)(vmc[vmc[pc+1]+i]);
                    Console.WriteLine(p);
                    ilc = 2;
                    break;
                case 2 : // loadr
                    regs[vmc[pc+1]] = vmc[pc+2];
                    ilc = 3;
                    break;
                case 3 : // cmpt
                    if ( regs[vmc[pc+1]] == vmc[pc+2] ) {
                        pc = vmc[pc+3];
                        ilc = 0;
                    } else {
                        ilc = 4;
                    }
                    break;
                case 4 : // incr
                    regs[vmc[pc+1]] += vmc[pc+2];
                    ilc = 3;
                    break;
                case 5 : // jump
                    pc = vmc[pc+1];
                    ilc = 0;
                    break;
                default :
                    Console.WriteLine("UNK INST");
                    break;    
            }
            pc += ilc;
        }

    }
}