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++ ) {
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);
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]);
vmc[(int)(myEnumerator.Key)] = (byte)val;
}
}
public void execCode() {
int pc = 0;
int ilc = 1;
bool cont = true;
int [] regs = new int[16];
while ( cont ) {
byte currInst = vmc[pc];
switch ( currInst ) {
case 0 :
cont = false;
break;
case 1 :
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 :
regs[vmc[pc+1]] = vmc[pc+2];
ilc = 3;
break;
case 3 :
if ( regs[vmc[pc+1]] == vmc[pc+2] ) {
pc = vmc[pc+3];
ilc = 0;
} else {
ilc = 4;
}
break;
case 4 :
regs[vmc[pc+1]] += vmc[pc+2];
ilc = 3;
break;
case 5 :
pc = vmc[pc+1];
ilc = 0;
break;
default :
Console.WriteLine("UNK INST");
break;
}
pc += ilc;
}
}
}