Added arithmetic and control flow functions.
It passes very simple test files.
This commit is contained in:
150
src/c0vm.js
150
src/c0vm.js
@@ -3,6 +3,15 @@ pc = 0;
|
|||||||
program = [];
|
program = [];
|
||||||
variables = [];
|
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
|
// Takes in a parsed .bc0 file and runs it
|
||||||
function execute(file) {
|
function execute(file) {
|
||||||
console.log("Beginning execution of file " + file);
|
console.log("Beginning execution of file " + file);
|
||||||
@@ -33,7 +42,12 @@ function execute(file) {
|
|||||||
break;
|
break;
|
||||||
case BIPUSH:
|
case BIPUSH:
|
||||||
pc += 2;
|
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;
|
break;
|
||||||
|
|
||||||
// Returning from a function
|
// Returning from a function
|
||||||
@@ -47,19 +61,147 @@ function execute(file) {
|
|||||||
var y = stack.pop();
|
var y = stack.pop();
|
||||||
var x = stack.pop();
|
var x = stack.pop();
|
||||||
console.log("Adding " + x + " and " + y);
|
console.log("Adding " + x + " and " + y);
|
||||||
stack.push((x+y) % 0x100);
|
stack.push((x+y) % 0x100000000);
|
||||||
break;
|
break;
|
||||||
case ISUB:
|
case ISUB:
|
||||||
pc++;
|
pc++;
|
||||||
var y = stack.pop();
|
var y = stack.pop();
|
||||||
var x = stack.pop();
|
var x = stack.pop();
|
||||||
stack.push((x-y) % 0x100);
|
stack.push((x-y) % 0x100000000);
|
||||||
break;
|
break;
|
||||||
case IMUL:
|
case IMUL:
|
||||||
pc++;
|
pc++;
|
||||||
var y = stack.pop();
|
var y = stack.pop();
|
||||||
var x = 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<<y);
|
||||||
|
break;
|
||||||
|
case ISHR:
|
||||||
|
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>>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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user