//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();