Skip to content
Snippets Groups Projects
vm_regs.c 2.93 KiB
Newer Older
Michal Privoznik's avatar
Michal Privoznik committed
#include <stdio.h>

typedef enum {
    A = 0,
    B,
Michal Privoznik's avatar
Michal Privoznik committed
} Registers;

typedef enum {
    FLAG_ZERO       = 1,
    FLAG_NEGATIVE   = 1 << 1,
} Flags;

typedef enum {
    OP_ADD,
    OP_ADD_VALUE,
    OP_HALT,
    OP_JMP_REL,
    OP_JMP_REL_NEGATIVE,
    OP_JMP_REL_NOT_EQUAL,
Michal Privoznik's avatar
Michal Privoznik committed
    OP_LOAD,
    OP_MOV,
    OP_XCHG,
Michal Privoznik's avatar
Michal Privoznik committed
    OP_NOP,
    OP_PRINT,
Michal Privoznik's avatar
Michal Privoznik committed
} OpCode;

static void
set_flags(int value, int *flags_register)
{
    int new_flags = 0;

Michal Privoznik's avatar
Michal Privoznik committed
    if (value == 0)
        new_flags |= FLAG_ZERO;
Michal Privoznik's avatar
Michal Privoznik committed
    if (value < 0)
        new_flags |= FLAG_NEGATIVE;

    *flags_register = new_flags;
Michal Privoznik's avatar
Michal Privoznik committed
}

int main() {
    int program[] = {
        OP_LOAD, A, 3,
        OP_LOAD, B, 5,
        OP_ADD, B,
        OP_PRINT, A,
        OP_LOAD, B, 1,
        OP_ADD, B,
        OP_PRINT, A,
        OP_LOAD, A, 0,
        OP_LOAD, B, 0,
        OP_PRINT, A,
        OP_ADD_VALUE, 3,
        OP_XCHG, A, B,
        OP_ADD_VALUE, 1,
        OP_TEST, 10,
        OP_XCHG, A, B,
        OP_JMP_REL_NOT_EQUAL, -16,
Michal Privoznik's avatar
Michal Privoznik committed
        OP_HALT
    };

    int registers[4] = { 0 };
Michal Privoznik's avatar
Michal Privoznik committed
    int flags_register = 0;
    int *ip = program;

    while (1) {
        OpCode op = *ip++;
        switch (op) {
        case OP_LOAD: {
            int idx = *ip++;
            registers[idx] = *ip++;
            set_flags(registers[idx], &flags_register);
            break;
        }
        case OP_ADD: {
            int val = registers[*ip++];
            registers[A] += val;
            set_flags(registers[A], &flags_register);
            break;
        }
        case OP_ADD_VALUE: {
            int val = *ip++;
            registers[A] += val;
Michal Privoznik's avatar
Michal Privoznik committed
            break;
        }
        case OP_JMP_REL: {
            int val = *ip++;
            ip += val;
Michal Privoznik's avatar
Michal Privoznik committed
            break;
        }
        case OP_NOP: {
            break;
        }
        case OP_TEST: {
            int val = *ip++;
            int new_val = val - registers[A];
            set_flags(new_val, &flags_register);
            break;
        }
        case OP_JMP_REL_NOT_EQUAL: {
            int val = *ip++;
            if (!(flags_register & FLAG_ZERO)) {
                ip += val;
            }
            break;
        }
        case OP_JMP_REL_NEGATIVE: {
            int val = *ip++;
            if (!(flags_register & FLAG_NEGATIVE)) {
                ip += val;
            }
            break;
        }
        case OP_MOV: {
            int dst = *ip++;
            int src = *ip++;
            registers[dst] = registers[src];
            break;
        }
        case OP_XCHG: {
            int r1 = *ip++;
            int r2 = *ip++;
            int tmp = registers[r1];
            registers[r1] = registers[r2];
            registers[r2] = tmp;
Michal Privoznik's avatar
Michal Privoznik committed
            break;
        }
        case OP_PRINT:
            printf("%d\n", registers[*ip++]);
            break;
        case OP_HALT:
            return 0;
        default:
            fprintf(stderr, "Unknown instruction %d\n", *ip);
            return -1;
        }
    }

    return 0;
}