360c390300
FossilOrigin-Name: d5fe8aa2c40bfaef4110c9b07c9fb35671ca31a6bedeafd79ee5d273bfd8aa1a
353 lines
6 KiB
D
353 lines
6 KiB
D
/* 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);
|
|
}
|