diff --git a/src/c0vm.js b/src/c0vm.js index 355c859..b1c8033 100755 --- a/src/c0vm.js +++ b/src/c0vm.js @@ -3,6 +3,15 @@ pc = 0; program = []; variables = []; +function doIf(shouldJump) { + if (shouldJump) { + var address_offset = (program[pc+1] * 0x1000) + program[pc+2]; + pc += address_offset; + } else { + pc += 3; + } +} + // Takes in a parsed .bc0 file and runs it function execute(file) { console.log("Beginning execution of file " + file); @@ -33,7 +42,12 @@ function execute(file) { break; case BIPUSH: pc += 2; - stack.push(program[pc-1]); + var val = program[pc-1]; + + // Do sign extension if necessary + if (val & 0x80 != 0) + val = -0x80 + (val & 0x7F); + stack.push(val); break; // Returning from a function @@ -47,19 +61,147 @@ function execute(file) { var y = stack.pop(); var x = stack.pop(); console.log("Adding " + x + " and " + y); - stack.push((x+y) % 0x100); + stack.push((x+y) % 0x100000000); break; case ISUB: pc++; var y = stack.pop(); var x = stack.pop(); - stack.push((x-y) % 0x100); + stack.push((x-y) % 0x100000000); break; case IMUL: pc++; var y = stack.pop(); var x = stack.pop(); - stack.push((x*y) % 0x100); + stack.push((x*y) % 0x100000000); + break; + case IDIV: + pc++; + var y = stack.pop(); + var x = stack.pop(); + if (y == 0) c0_arith_error("Divide by zero"); + if (x == INT_MIN && y == -1) c0_arith_error("Arithmetic overflow"); + + // This does int division. + // As I understand it, the ~~ is treated as the identity on integers + // which forces the type to int, not float + stack.push(~~(x/y)); + break; + case IREM: + pc++; + var y = stack.pop(); + var x = stack.pop(); + if (y == 0) c0_arith_error("Divide by zero"); + if (x == INT_MIN && y == -1) c0_arith_error("Arithmetic overflow"); + stack.push(x%y); + break; + case IAND: + pc++; + var y = stack.pop(); + var x = stack.pop(); + stack.push(x&y); + break; + case IOR: + pc++; + var y = stack.pop(); + var x = stack.pop(); + stack.push(x|y); + break; + case IXOR: + pc++; + var y = stack.pop(); + var x = stack.pop(); + stack.push(x^y); + break; + case ISHL: + pc++; + var y = stack.pop(); + var x = stack.pop(); + if (y < 0 || y > 31) c0_arith_error("Shifting by too many bits"); + stack.push(x< 31) c0_arith_error("Shifting by too many bits"); + stack.push(x>>y); + break; + + // Operations on local variables + + case VLOAD: + pc += 2; + var index = program[pc-1]; + stack.push(variables[index]); + break; + case VSTORE: + pc +=2 ; + var index = program[pc-1]; + variables[index] = stack.pop(); + break; + case ACONST_NULL: + pc++; + stack.push(0); + break; + case ILDC: + pc += 3; + var c1 = program[pc-2]; + var c2 = program[pc-1]; + var index = (c1 * 0x1000) + c2; + + stack.push(file.int_pool[index]); + break; + case ALDC: + console.log("Error: I don't know how to handle ALDC yet"); + return; + + // Control flow + case NOP: + pc++; + break; + case IF_CMPEQ: + var y = stack.pop(); + var x = stack.pop(); + doIf(y == x); + break; + case IF_CMPNE: + var y = stack.pop(); + var x = stack.pop(); + doIf(y != x); + break; + case IF_CMPLT: + var y = stack.pop(); + var x = stack.pop(); + doIf(y > x); + break; + case IF_CMPGE: + var y = stack.pop(); + var x = stack.pop(); + doIf(y <= x); + break; + case IF_CMPGT: + var y = stack.pop(); + var x = stack.pop(); + doIf(y < x); + break; + case IF_CMPLE: + var y = stack.pop(); + var x = stack.pop(); + doIf(y >= x); + break; + case GOTO: + doIf(true); + break; + case ATHROW: + pc++; + c0_user_error(stack.pop()); + break; + case ASSERT: + pc++; + var a = stack.pop(); + if (stack.pop() == 0) + c0_assertion_failure(a); break; default: