Created
April 3, 2012 16:04
-
-
Save troufster/2293191 to your computer and use it in GitHub Desktop.
generic cpu emulator :P
This file contains hidden or 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
//Mask with 16 bits | |
var bitMask = 0xFFFF; | |
var cmdAlias = {}; | |
var errAlias = { | |
0x1 : 'Unknown instruction', | |
0x2 : 'Stack overflow' | |
} | |
var CPU = { | |
ERR : 0, | |
STA: [], | |
PWR : 0, | |
SP : 16, | |
PC : 0, | |
R : { a : 0, b : 0, c : 0, | |
x : 0, y : 0, z : 0 }, | |
O : 0, | |
MEM : { | |
}, | |
_nextOp : function(n) { | |
return CPU.MEM[CPU.PC+ (n||1)]; | |
}, | |
_isReg : function(r) { | |
var regs = Object.keys(CPU.R); | |
return regs.indexOf(r) > -1; | |
} | |
, | |
OP : { | |
0x0 : /* INC */ function() { | |
var reg = CPU._nextOp(); | |
var R = CPU.R; | |
R[reg]++; | |
if(R[reg] > bitMask) { | |
CPU.O = 0x1; | |
R[reg] = 0xFF; | |
} | |
CPU.PC+=2; | |
}, | |
0x1 : /* JNO */ function() { | |
if(!CPU.O) { | |
var mem = CPU.MEM[CPU.PC+1]; | |
CPU.PC = mem; | |
return; | |
} | |
CPU.PC+=2; | |
}, | |
0x2 : /* HLT */ function() { | |
CPU.PWR = 0; | |
}, | |
0x3 : /* DEC */ function(){ | |
var reg = CPU._nextOp(); | |
var R = CPU.R; | |
R[reg]--; | |
if(R[reg] < 0x00) { | |
CPU.O = 0x1; | |
R[reg] = 0x00; | |
} | |
CPU.PC+=2; | |
}, | |
0x4 : /* ROF */ function() { | |
CPU.O = 0x0; | |
CPU.PC++; | |
}, | |
0x5 : /* SET */ function() { | |
var R = CPU.R; | |
var dest = CPU._nextOp(1); | |
var val = CPU._nextOp(2); | |
var destReg = CPU._isReg(dest); | |
var valReg = CPU._isReg(val); | |
val = valReg ? R[val] : val; | |
if(destReg) { | |
R[dest] = val & bitMask; | |
} else { | |
CPU.MEM[dest] = val & bitMask; | |
} | |
CPU.PC+=3; | |
}, | |
0x6 : /* ADD */ function() { | |
var R = CPU.R; | |
var M = CPU.MEM; | |
var dest = CPU._nextOp(1); | |
var val = CPU._nextOp(2); | |
var destReg = CPU._isReg(dest); | |
var valReg = CPU._isReg(val); | |
val = valReg ? R[val] : val; | |
val = val & bitMask; | |
var target = destReg ? R : M; | |
var of = (target[dest] + val) - bitMask; | |
if(of > 0) { | |
CPU.O = of & bitMask; | |
} | |
target[dest] += val; | |
target[dest] = target[dest] & bitMask; | |
CPU.PC +=3; | |
}, | |
0x7 : /* PUSH */ function() { | |
var R = CPU.R; | |
var val = CPU._nextOp(1); | |
var valReg = CPU._isReg(val); | |
val = valReg ? R[val] : val; | |
CPU.STA.push(val); | |
CPU.SP--; | |
if(CPU.SP < 0) { | |
CPU.ERR = 0x2; | |
} | |
CPU.PC +=2; | |
}, | |
0x8 : /* POP */ function() { | |
var R = CPU.R; | |
var M = CPU.MEM; | |
var dest = CPU._nextOp(1); | |
var destReg = CPU._isReg(dest); | |
var target = destReg ? R : M; | |
target[dest] = CPU.STA.pop(); | |
CPU.SP++; | |
CPU.PC +=2; | |
}, | |
0x9 : /*PEEK*/ function() { | |
var R = CPU.R; | |
var M = CPU.MEM; | |
var dest = CPU._nextOp(1); | |
var destReg = CPU._isReg(dest); | |
var target = destReg ? R : M; | |
target[dest] = CPU.STA[CPU.STA.length-1]; | |
CPU.PC +=2; | |
} | |
}, | |
CMAP : { | |
"INC" : 0x0, | |
"JNO" : 0x1, | |
"HLT" : 0x2, | |
"DEC" : 0x3, | |
"ROF" : 0x4, | |
"SET" : 0x5, | |
"ADD" : 0x6, | |
"PUSH": 0x7, | |
"POP" : 0x8, | |
"PEEK": 0x9 | |
}, | |
Run : function() { | |
CPU.PWR = 1; | |
while(CPU.PWR != 0) { | |
//Fetch | |
var op = CPU.MEM[CPU.PC]; | |
if(typeof op == 'undefined') { | |
CPU.ERR = 0x1; | |
CPU.Halt(); | |
break; | |
}; | |
if(CPU.ERR > 0) { | |
CPU.Halt(); | |
break; | |
} | |
//Dispatch | |
CPU.OP[op](); | |
console.log(CPU.R['a'],CPU.R['b'],CPU.R['c']); | |
} | |
}, | |
Halt : function() { | |
CPU.PWR = 0; | |
console.log("Halted, ERR:", errAlias[CPU.ERR]); | |
} | |
} | |
function Asm(asm) { | |
var lines = asm.split('\n') | |
var regs = Object.keys(CPU.R); | |
var p = 0x0; | |
for(var i = 0, l = lines.length; i < l; i++) { | |
//console.log(lines[i],i, lines.length); | |
var token = lines[i].replace(/^\s+|\s+$/, ''); | |
//console.log(token); | |
if(token.indexOf(' ') > -1) { | |
//Arguments command | |
var parts; | |
if(token.indexOf(',') > -1) { | |
//Multiple arguments | |
parts = token.split(' '); | |
parts = [parts.shift(), parts.join('')]; | |
var args = parts[1].replace(' ','').split(','); | |
CPU.MEM[p] = CPU.CMAP[parts[0]]; | |
for(var a = 0, al = args.length; a < al; a ++ ) { | |
var isReg = regs.indexOf(args[a]) > -1; | |
CPU.MEM[p+(a+1)] = isReg ? args[a] : args[a] & bitMask; | |
} | |
p += args.length + 1 ; | |
continue; | |
} | |
parts = token.split(' '); | |
CPU.MEM[p] = CPU.CMAP[parts[0]]; | |
var isReg = regs.indexOf(parts[1]) > -1; | |
CPU.MEM[p+1] = isReg ? parts[1] : parts[1] & bitMask; | |
p +=2; | |
} else { | |
if(token.indexOf(':') > -1) { | |
cmdAlias[token.replace(':','')] = p; | |
continue; | |
} | |
//Single command | |
var cmd = CPU.CMAP[token] | |
if(!cmd) { | |
continue; | |
} | |
CPU.MEM[p] = cmd; | |
p +=1; | |
} | |
} | |
} | |
var asm = | |
"INC R0 \n\ | |
JNO 0x0 \n\ | |
ROF \n\ | |
DEC R0 \n\ | |
JNO 0x3 \n\ | |
SET R3,0xFF \n\ | |
SET R1,0xAB \n\ | |
SET R2,0x0F \n\ | |
SET 0xFF,R2 \n\ | |
HLT"; | |
var asm2 = | |
"SET a,0xFFFF \n\ | |
SET b,0xAB \n\ | |
SET c,0xFF \n\ | |
SET 0xFF,a \n\ | |
ADD b,a \n\ | |
PUSH b \n\ | |
ADD b,1 \n\ | |
SET a,b \n\ | |
POP b \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFB \n\ | |
PUSH 0xFAF1 \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PUSH 0xFAFA \n\ | |
PEEK 0xFE \n\ | |
HLT"; | |
//Assemble & Load into cpu | |
Asm(asm2); | |
CPU.Run(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment