Skip to content

Instantly share code, notes, and snippets.

@troufster
Created April 3, 2012 16:04
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 troufster/2293191 to your computer and use it in GitHub Desktop.
Save troufster/2293191 to your computer and use it in GitHub Desktop.
generic cpu emulator :P
//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