add a D implementation of Nga (32-bit only)
FossilOrigin-Name: d5fe8aa2c40bfaef4110c9b07c9fb35671ca31a6bedeafd79ee5d273bfd8aa1a
This commit is contained in:
parent
075fbd6500
commit
360c390300
2 changed files with 354 additions and 0 deletions
|
@ -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)
|
||||
|
||||
================================================================
|
||||
|
|
353
vm/nga-d/nga.d
Normal file
353
vm/nga-d/nga.d
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue