Skip to content

Instantly share code, notes, and snippets.

@thedeemon
Created November 21, 2018 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thedeemon/a1701a837ebe403eb7740dc32107038c to your computer and use it in GitHub Desktop.
Save thedeemon/a1701a837ebe403eb7740dc32107038c to your computer and use it in GitHub Desktop.
bytecode VM targeted by Leo compiler
module lvm2;
import std.stdio;
enum MODSHIFT = 8;
enum RRR = 0 << MODSHIFT;
enum RRP = 1 << MODSHIFT;
enum RRV = 2 << MODSHIFT;
enum RPR = 4 << MODSHIFT;
enum RPP = 5 << MODSHIFT;
enum RPV = 6 << MODSHIFT;
enum RVR = 8 << MODSHIFT;
enum RVP = 9 << MODSHIFT;
enum RVV = 10 << MODSHIFT;
enum PRR = 16 << MODSHIFT;
enum PRP = 17 << MODSHIFT;
enum PRV = 18 << MODSHIFT;
enum PPR = 20 << MODSHIFT;
enum PPP = 21 << MODSHIFT;
enum PPV = 22 << MODSHIFT;
enum PVR = 24 << MODSHIFT;
enum PVP = 25 << MODSHIFT;
enum PVV = 26 << MODSHIFT;
//#define CMDSHIFT 0
//commands
enum ADD = 1; //d, a1, a2 : d = a1 + a2 b
enum MUL = 2; //d, a1, a2 : d = a1 * a2 c
enum MOD = 3; //d, a1, a2 : d = a1 % a2 d
enum SUB = 4; //d, a1, a2 : d = a1 - a2 e
enum DIV = 5; //d, a1, a2 : d = a1 / a2 f
enum XOR = 6; //d, a1, a2 : d = a1 ^ a2 g
enum MOV = 7; //d, a1 : d = a1 h
enum MOVB = 8; //d, a1 : d = a1 i
enum JMPLE = 9; //addr, a1, a2 : if a1 < a2 ip = addr j
enum JMPEQ = 10; //addr, a1, a2 : if a1 == a2 ip = addr k
enum JMP = 11; //addr : ip = addr l
enum PRINT = 12; //x, a1 : print a1 m
enum NEW = 13; //d, a1 : d = malloc= a) n
enum CALL = 14; //addr, a1 : fp += a1, call addr o
enum RET = 15; //: return from call p
enum ADD_RRR = 0; //d, a1, a2 :as ADD but all operands are regs a
enum JMPLE_RR = 17; //addr, a1, a2 : ~ r
enum ADD_RRV = 18; //d, a1, a2 : r = r + v s
enum MOV_RV = 19; //d, a1 : r = v t
enum MOV_RR = 20; //d, a1 : r = r u
enum INC = 21; //d, x, x : r++ v
enum INC4 = 22; //d, x, x : r += 4 w
enum PRCHAR = 23; //x, a1 : print a1
enum POSTMSG = 24; //msg, a1, a2: PostMessage= hwnd=a1, msg, param=a2)
enum BR = 0 << MODSHIFT;
enum BP = 1 << MODSHIFT;
enum BV = 2 << MODSHIFT;
enum AR = 0 << MODSHIFT;
enum AP = 4 << MODSHIFT;
enum AV = 8 << MODSHIFT;
enum DR = 0 << MODSHIFT;
enum DP = 16 << MODSHIFT;
struct LVM2 {
struct context_t {
int ip, fp, hp;
};
int[] frame;
ubyte[] heap;
context_t[] callstack;
void init(int stacksize, int heapsize) {
frame.length = stacksize / 4;
heap.length = heapsize;
callstack.length = 10000;
}
void Run(int[] code, void *params, string logname) {
int ip = 0, hp = 0, fp = 0, csp = 0;
frame[0] = cast(int)params;
File f;// = stdout;//
int *dest; int source1, source2;
const int codelen = code.length;
while(ip < codelen) {
const int cmd = code[ip];
enum load_d = "if (cmd & DP) dest = cast(int*)frame[fp + code[ip+1]]; else dest = &frame[fp + code[ip+1]];";
enum load_a1 = q{
switch (cmd & (12<<MODSHIFT)) {
case AR: source1 = frame[fp + code[ip+2]]; break;
case AP: source1 = *cast(int*)frame[fp + code[ip+2]]; break;
case AV: source1 = code[ip+2]; break;
default: throw new Exception("LVM2: bad A1 value");
}
};
enum load_a2 = q{
switch (cmd & (3 << MODSHIFT)) {
case BR: source2 = frame[fp + code[ip+3]]; break;
case BP: source2 = *cast(int*)frame[fp + code[ip+3]]; break;
case BV: source2 = code[ip+3]; break;
default: throw new Exception("LVM2: bad A2 value");
}
};
switch(cmd & 0xFF) {
case ADD: mixin(load_d); mixin(load_a1); mixin(load_a2); *dest = source1 + source2; ip += 4; break;
case MUL: mixin(load_d); mixin(load_a1); mixin(load_a2); *dest = source1 * source2; ip += 4; break;
case MOD: mixin(load_d); mixin(load_a1); mixin(load_a2); *dest = source1 % source2; ip += 4; break;
case SUB: mixin(load_d); mixin(load_a1); mixin(load_a2); *dest = source1 - source2; ip += 4; break;
case DIV: mixin(load_d); mixin(load_a1); mixin(load_a2); *dest = source1 / source2; ip += 4; break;
case XOR: mixin(load_d); mixin(load_a1); mixin(load_a2); *dest = source1 ^ source2; ip += 4; break;
case MOV: mixin(load_d); mixin(load_a1); *dest = source1; ip += 3; break;
case MOVB: mixin(load_d); mixin(load_a1); *cast(ubyte*)dest = cast(ubyte)source1; ip += 3; break;
case JMPLE: mixin(load_a1); mixin(load_a2); if (source1 < source2) ip = code[ip+1]; else ip += 4; break;
case JMPEQ: mixin(load_a1); mixin(load_a2); if (source1 == source2) ip = code[ip+1]; else ip += 4; break;
case JMP: ip = code[ip+1]; break;
case PRINT: if (!f.isOpen) f.open(logname,"a"); mixin(load_a1); f.writef("%d ", source1); ip += 3; break;
case PRCHAR: if (!f.isOpen) f.open(logname,"a"); mixin(load_a1); f.writef("%c" , cast(char)source1); ip += 3; break;
case NEW: mixin(load_d); mixin(load_a1); *dest = cast(int)&heap[hp]; hp += source1; ip += 3; break;
case CALL:
mixin(load_a1);
callstack[csp].fp = fp;
callstack[csp].hp = hp;
callstack[csp].ip = ip + 3;
csp++;
fp += source1;
ip = code[ip+1];
break;
case RET:
if (csp<1) return;
csp--;
fp = callstack[csp].fp;
hp = callstack[csp].hp;
ip = callstack[csp].ip;
break;
case ADD_RRR: frame[fp + code[ip+1]] = frame[fp + code[ip+2]] + frame[fp + code[ip+3]]; ip += 4; break;
case ADD_RRV: frame[fp + code[ip+1]] = frame[fp + code[ip+2]] + code[ip+3]; ip += 4; break;
case MOV_RV: frame[fp + code[ip+1]] = code[ip+2]; ip += 3; break;
case MOV_RR: frame[fp + code[ip+1]] = frame[fp + code[ip+2]]; ip += 3; break;
case JMPLE_RR: if (frame[fp + code[ip+2]] < frame[fp + code[ip+3]]) ip = code[ip+1]; else ip += 4; break;
case INC: frame[fp + code[ip+1]]++; ip += 4; break;
case INC4: frame[fp + code[ip+1]] += 4; ip += 4; break;
default: ip++;
}
}//while
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment