Last active
July 2, 2021 05:21
-
-
Save tangentstorm/1520860029844d1459f62140608f2036 to your computer and use it in GitHub Desktop.
ASM vm... This started as an attempt at a bootstrapping virtual machine, then I got caught up with the idea that bytecode could be human readable, and it probably got a bit out of hand.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const DATA=0, CALL=1, WORK=2, TEMP=3 | |
class Worker { | |
vm = null // virtual machine | |
w = 0 // worker number | |
f = 0 // function pointer | |
e = 0 // execution pointer | |
t = 0 // current token in function | |
s = "" // source (input string/data) | |
i = -1 // read pointer | |
x = 0 // first arg | |
y = 0 // second arg | |
z = 0 // third arg | |
constructor(vm, n) { | |
this.vm = vm | |
this.n = n | |
this.d = [[],[],[],[],[]] // stacks: DATA, CALL (for system), WORK, TEMP (for user) | |
} | |
// push and pop to the stacks: | |
push(s,v) { this.d[s].push(v) } pop(s) { return this.d[s].pop() } | |
dx(v) { this.push(DATA, v) } xd() { return this.pop(DATA) } | |
cx(v) { this.push(CALL, v) } xc() { return this.pop(CALL) } | |
wx(v) { this.push(WORK, v) } xw() { return this.pop(WORK) } | |
tx(v) { this.push(TEMP, v) } xt() { return this.pop(TEMP) } | |
// -- parser support ------------------------------------------------------ | |
// move execution pointer and get new instruction | |
vmi(j) { this.t=this.vm.f[this.d][this.e+=j]; return this.t } | |
// // process a hex number | |
// hex() { | |
// let ix=-1, r = 0; const hex = "0123456789ABCDEF_" | |
// while(0>=(ix=hex.indexOf(this.vmi(1)))) { r = ix===16? -r : ix + r << 4 } | |
// this.vmi(-1); | |
// return t } | |
ops = { | |
// read and write the registers | |
'x':()=> this.dx(this.x), 'X':()=> this.x=this.xd(), | |
'y':()=> this.dx(this.y), 'Y':()=> this.y=this.xd(), | |
'z':()=> this.dx(this.z), 'Z':()=> this.y=this.xd(), | |
'i':()=> this.dx(this.i), 'I':()=> this.i=this.xd(), | |
's':()=> this.dx(this.s), 'S':()=> this.s=this.xd(), | |
// current and next values from src | |
'v':()=> this.dx(this.s[this.i]||null), | |
'V':()=> this.dx(this.s[this.i+1]||null), | |
// worker id | |
'W':()=> this.dx(this.n), | |
// truthy/falsy (we use 0 and 1) | |
'?':()=> this.dx(+!!this.xd()), | |
'~':()=> this.dx(~this.xd()), | |
// hex digits | |
'_':()=> this.dx(-this.xd()), | |
'$':()=> this.dx(0), | |
'0':()=> this.dx(0+this.xd()<<4), '8':()=> this.dx( 8+this.xd()<<4), | |
'1':()=> this.dx(1+this.xd()<<4), '9':()=> this.dx( 9+this.xd()<<4), | |
'2':()=> this.dx(2+this.xd()<<4), 'A':()=> this.dx(10+this.xd()<<4), | |
'3':()=> this.dx(3+this.xd()<<4), 'B':()=> this.dx(11+this.xd()<<4), | |
'4':()=> this.dx(4+this.xd()<<4), 'C':()=> this.dx(12+this.xd()<<4), | |
'5':()=> this.dx(5+this.xd()<<4), 'D':()=> this.dx(13+this.xd()<<4), | |
'6':()=> this.dx(6+this.xd()<<4), 'E':()=> this.dx(14+this.xd()<<4), | |
'7':()=> this.dx(7+this.xd()<<4), 'F':()=> this.dx(15+this.xd()<<4), | |
// jump to TOS if NOS is truthy. otherwise drop both. | |
'j':()=> { let rel = 0|this.dx(); if(!!this.dx()) this.i += rel }, | |
// unconditional relative jump | |
'J':()=> { this.i += 0|this.dx() }, | |
// dup | |
"d":()=> { let w=this.d[WORK],l=w.length; if(l){ this.dx(d[l-1]) }}, | |
// temporary list | |
"[":()=> { this.tx(this.d[DATA]); this.d[DATA]=[] }, | |
"]":()=> { let t = this.d[DATA]; this.d[DATA]=this.xt(); this.dx(t) }, | |
// write item to work buffer | |
",":()=> this.wx(this.xd()), | |
// length of the work buffer (like "HERE" in forth) | |
'#':()=> this.dx(this.wx.length), | |
// call/return | |
'c':()=> this.cx(this.p), 'r':()=> this.p = this.xc(), | |
} | |
// -- functions ----------------------------------------------------------- | |
// -- arithmetic ---------------------------------------------------------- | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment