import instr;

import std.array;
import std.stdio;
import std.string;

class CPU {
public:
    uint[32] registers;
    uint[4096] memory;
    uint[] program;
    uint pc, cycles;
    bool running;

    this(uint[] p) {
        pc             = 0;
        registers[]    = 0;
        memory[]       = 0;
        running        = true;

        program        = p;
    }

    void tick() {
        if (pc < program.length) {
            Instr i = Instr.decode(program[pc]);
            i.compute(this);
        } else {
            running = false;
        }
        pc++;
    }

    void run() {
        while (running) {
            tick();
        }
    }

    /* Stop the program. */
    void halt() {
        writefln("HALTING PROGRAM.");
        running = false;
    }

    /* Print all the registers at this state. */
    void print_registers() {
        writef("  registers([");
        for (uint i = 0; i < 32; i++) {
            if (i != 0)
                writef(", ");

            writef("%x", registers[i]);
        }
        writefln("])");
    }

    /* Print the value of a register. */
    void print_line(uint x) {
        printf("PROGRAM OUTPUT: %d\n", x);
    }
}

void main(string[] args) {
    if (args.length < 2) {
        writefln("Usage: %s [file]", args[0]);
        return;
    }
    writefln("Opening %s", args[1]);
    auto f = File(args[1], "r");
    uint psize = cast(uint)f.size >> 2;
    uint[] program;
    program.length = psize;
    uint i = 0;

    foreach(ubyte[] buffer; f.byChunk(4)) {
        uint word = buffer[3] |
            buffer[2] << 0x08 |
            buffer[1] << 0x10 |
            buffer[0] << 0x18;
        program[i] = word;
        i ++;
    }
    CPU cpu = new CPU(program);
    writefln("Executing program...");
    (new CPU(program)).run();
    writefln("");
}
