A basic Virtual Machine for Experimentation






1.10/5 (40 votes)
May 14, 2003

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; } } }