diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 0789118..1827abf 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -14,5 +14,6 @@ - err:notfound message no longer in C (C) (sevan) - add -v for verbose mode (C) - now skip execuion of NOP instructions (C) +- added an implementation of Nga in D (D) ================================================================ diff --git a/vm/nga-d/nga.d b/vm/nga-d/nga.d new file mode 100644 index 0000000..d3fe27f --- /dev/null +++ b/vm/nga-d/nga.d @@ -0,0 +1,353 @@ +/* nga.d, (c) charles childers */ + +import std.stdio; +import std.stdint; +import core.stdc.stdlib; + +enum int_MIN = -2147483647; +enum int_MAX = 2147483646; + +enum IMAGE_SIZE = 65536; /* Amount of RAM, in ints */ +enum ADDRESSES = 256; /* Depth of address stack */ +enum STACK_DEPTH = 256; /* Depth of data stack */ + +int sp, rp, ip; /* Stack and instruction pointers */ +int[STACK_DEPTH] data; /* The data stack */ +int[ADDRESSES] address; /* The address stack */ +int[IMAGE_SIZE] memory; /* Image Memory */ + +void stack_push(int value) +{ + sp += 1; + data[sp] = value; +} + +int stack_pop() +{ + sp -= 1; + return data[sp + 1]; +} + +void execute(int c) +{ + int i; + ip = c; + while (ip < IMAGE_SIZE) + { + process_bundle(memory[ip]); + ip += 1; + } +} + +void load_image() +{ + FILE* fp; + long fileLen; + if ((fp = fopen("ngaImage", "rb")) !is null) + { + fseek(fp, 0, SEEK_END); + fileLen = ftell(fp); + rewind(fp); + fread(memory.ptr, 1, fileLen, fp); + fclose(fp); + } +} + +void prepare_vm() +{ + ip = sp = rp = 0; + foreach (i; 0 .. IMAGE_SIZE) + memory[i] = 0; /* NO - nop instruction */ + foreach (i; 0 .. STACK_DEPTH) + data[i] = 0; + foreach (i; 0 .. ADDRESSES) + address[i] = 0; +} + +void inst_no() {} + +void inst_li() +{ + ip += 1; + stack_push(memory[ip]); +} + +void inst_du() +{ + stack_push(data[sp]); +} + +void inst_dr() +{ + stack_pop(); +} + +void inst_sw() +{ + int a = data[sp]; + data[sp] = data[sp - 1]; + data[sp - 1] = a; +} + +void inst_pu() +{ + rp += 1; + address[rp] = stack_pop(); +} + +void inst_po() +{ + stack_push(address[rp]); + rp -= 1; +} + +void inst_ju() +{ + ip = stack_pop() - 1; +} + +void inst_ca() +{ + rp += 1; + address[rp] = ip; + ip = stack_pop() - 1; +} + +void inst_cc() +{ + int a, b; + a = stack_pop(); /* Target */ + b = stack_pop(); /* Flag */ + if (b != 0) + { + rp += 1; + address[rp] = ip; + ip = a - 1; + } +} + +void inst_re() +{ + ip = address[rp]; + rp -= 1; +} + +void inst_eq() +{ + data[sp - 1] = (data[sp - 1] == data[sp]) ? -1 : 0; + inst_dr(); +} + +void inst_ne() +{ + data[sp - 1] = (data[sp - 1] != data[sp]) ? -1 : 0; + inst_dr(); +} + +void inst_lt() +{ + data[sp - 1] = (data[sp - 1] < data[sp]) ? -1 : 0; + inst_dr(); +} + +void inst_gt() +{ + data[sp - 1] = (data[sp - 1] > data[sp]) ? -1 : 0; + inst_dr(); +} + +void inst_fe() +{ + switch (data[sp]) + { + case -1: data[sp] = sp - 1; break; + case -2: data[sp] = rp; break; + case -3: data[sp] = IMAGE_SIZE; break; + case -4: data[sp] = int_MIN; break; + case -5: data[sp] = int_MAX; break; + default: data[sp] = memory[data[sp]]; break; + } +} + +void inst_st() +{ + if (data[sp] <= IMAGE_SIZE && data[sp] >= 0) + { + memory[data[sp]] = data[sp - 1]; + inst_dr(); + inst_dr(); + } + else + { + ip = IMAGE_SIZE; + } +} + +void inst_ad() +{ + data[sp - 1] += data[sp]; + inst_dr(); +} + +void inst_su() +{ + data[sp - 1] -= data[sp]; + inst_dr(); +} + +void inst_mu() +{ + data[sp - 1] *= data[sp]; + inst_dr(); +} + +void inst_di() +{ + int a = data[sp]; + int b = data[sp - 1]; + data[sp] = b / a; + data[sp - 1] = b % a; +} + +void inst_an() +{ + data[sp - 1] = data[sp] & data[sp - 1]; + inst_dr(); +} + +void inst_or() +{ + data[sp - 1] = data[sp] | data[sp - 1]; + inst_dr(); +} + +void inst_xo() +{ + data[sp - 1] = data[sp] ^ data[sp - 1]; + inst_dr(); +} + +void inst_sh() +{ + int y = data[sp]; + int x = data[sp - 1]; + if (data[sp] < 0) + data[sp - 1] = data[sp - 1] << (0 - data[sp]); + else + { + if (x < 0 && y > 0) + data[sp - 1] = x >> y | ~(~0U >> y); + else + data[sp - 1] = x >> y; + } + inst_dr(); +} + +void inst_zr() +{ + if (data[sp] == 0) + { + inst_dr(); + ip = address[rp]; + rp -= 1; + } +} + +void inst_ha() +{ + ip = IMAGE_SIZE; +} + +void inst_ie() +{ + stack_push(2); +} + +void inst_iq() +{ + if (data[sp] == 0) + { + inst_dr(); + stack_push(0); + stack_push(0); + } + else if (data[sp] == 1) + { + inst_dr(); + stack_push(1); + stack_push(1); + } +} + +void inst_ii() +{ + int c; + if (data[sp] == 0) + { + inst_dr(); + writef("%c", cast(char)stack_pop()); + } + else if (data[sp] == 1) + { + c = getchar(); + if (c < 0) exit(0); + inst_dr(); + stack_push(c); + } + else + { + inst_dr(); + } +} + +void process(int opcode) { + switch (opcode) { + case 0: inst_no(); break; + case 1: inst_li(); break; + case 2: inst_du(); break; + case 3: inst_dr(); break; + case 4: inst_sw(); break; + case 5: inst_pu(); break; + case 6: inst_po(); break; + case 7: inst_ju(); break; + case 8: inst_ca(); break; + case 9: inst_cc(); break; + case 10: inst_re(); break; + case 11: inst_eq(); break; + case 12: inst_ne(); break; + case 13: inst_lt(); break; + case 14: inst_gt(); break; + case 15: inst_fe(); break; + case 16: inst_st(); break; + case 17: inst_ad(); break; + case 18: inst_su(); break; + case 19: inst_mu(); break; + case 20: inst_di(); break; + case 21: inst_an(); break; + case 22: inst_or(); break; + case 23: inst_xo(); break; + case 24: inst_sh(); break; + case 25: inst_zr(); break; + case 26: inst_ha(); break; + case 27: inst_ie(); break; + case 28: inst_iq(); break; + case 29: inst_ii(); break; + default: writef("\nERROR: %d\n", opcode); /* Handle unknown opcode */ exit(1); break; + } +} + +void process_bundle(int opcode) { + process(opcode & 0xFF); + process((opcode >> 8) & 0xFF); + process((opcode >> 16) & 0xFF); + process((opcode >> 24) & 0xFF); +} + +void main(string[] args) +{ + prepare_vm(); + load_image(); + execute(0); + while (sp > 0) { writef("%d ", stack_pop()); } writef("\n"); + exit(0); +}