|
#include <stdint.h> |
|
#include <stdio.h> |
|
|
|
#include "register.h" |
|
|
|
#define log(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) |
|
|
|
#define fst(X) ((X) >> 8) |
|
#define snd(X) ((X) & 0xFF) |
|
|
|
#define REG_SIZE 0x100 |
|
#define REG_MEM_MAX_ADDR 0xFF |
|
#define MEM_SIZE 0x10000 |
|
#define MEM_PROG_START 0xFEFF |
|
|
|
struct machine { |
|
uint16_t pc; |
|
uint16_t reg[REG_SIZE]; |
|
uint16_t mem[MEM_SIZE]; |
|
}; |
|
|
|
#define stack_ctr(M) ((M).mem[MEM_SIZE - 1]) |
|
#define stack_head(M) ((M).mem[MEM_SIZE - 1 - stack_ctr(M)]) |
|
|
|
uint16_t |
|
get_next_instruction(struct machine *m) |
|
{ |
|
return m->mem[MEM_PROG_START - m->pc++]; |
|
} |
|
|
|
int |
|
main(int argc, char **argv) |
|
{ |
|
uint16_t inst; |
|
uint16_t *memp; |
|
char word[2]; |
|
FILE *f; |
|
|
|
struct machine m = {0, {0}, {0}}; |
|
|
|
f = fopen("prog.rm", "r"); |
|
m.reg[REG_MEM_MAX_ADDR] = MEM_PROG_START; |
|
while (fread(word, 2, 1, f)) { |
|
m.mem[m.reg[REG_MEM_MAX_ADDR]--] = (word[0] << 8) + word[1]; |
|
} |
|
|
|
while (1) { |
|
inst = get_next_instruction(&m); |
|
switch (fst(inst)) { |
|
case INSTR_INC: |
|
m.reg[snd(inst)]++; |
|
break; |
|
case INSTR_JZD: |
|
if (m.reg[snd(inst)]) { |
|
m.reg[snd(inst)]--; |
|
m.pc++; |
|
break; |
|
} |
|
/* FALLTHROUGH */ |
|
case INSTR_JMP: |
|
m.pc = get_next_instruction(&m); |
|
break; |
|
case INSTR_RDC: |
|
memp = &m.mem[m.reg[snd(inst)]]; |
|
fread(memp, 1, 1, stdin) || (*memp = 0); |
|
break; |
|
case INSTR_WRC: |
|
memp = &m.mem[m.reg[snd(inst)]]; |
|
fwrite(memp, 1, 1, stdout); |
|
break; |
|
case INSTR_LOD: |
|
inst = get_next_instruction(&m); |
|
memp = &m.mem[m.reg[snd(inst)]]; |
|
m.reg[fst(inst)] = *memp; |
|
break; |
|
case INSTR_STO: |
|
inst = get_next_instruction(&m); |
|
memp = &m.mem[m.reg[snd(inst)]]; |
|
*memp = m.reg[fst(inst)]; |
|
break; |
|
case INSTR_GSB: |
|
if (stack_ctr(m)++ >= 0xFF) { |
|
log("Stack overflow\n"); |
|
return 1; |
|
} |
|
stack_head(m) = m.pc + 1; |
|
m.pc = get_next_instruction(&m); |
|
break; |
|
case INSTR_RET: |
|
if (stack_ctr(m)) { |
|
m.pc = stack_head(m); |
|
--stack_ctr(m); |
|
} else { |
|
return 0; |
|
} |
|
break; |
|
default: |
|
log("ERROR at %d: bad instruction %c%c\n", |
|
m.pc - 1, |
|
fst(inst), snd(inst)); |
|
return 1; |
|
} |
|
} |
|
} |