diff options
Diffstat (limited to 'src/orgaemu.c')
-rw-r--r-- | src/orgaemu.c | 109 |
1 files changed, 97 insertions, 12 deletions
diff --git a/src/orgaemu.c b/src/orgaemu.c index be53a22..b824415 100644 --- a/src/orgaemu.c +++ b/src/orgaemu.c @@ -5,8 +5,20 @@ #define MEM_SIZE 0xffff -static uint16_t *stack = NULL; -static size_t stack_ptr = 0; +static uint16_t *mem = NULL, *stack = NULL, *rstack = NULL; +static size_t stack_ptr = 0, rstack_ptr = 0; + +static int +fail(void) +{ + if (mem != NULL) + free(mem); + if (stack != NULL) + free(stack); + if (rstack != NULL) + free(rstack); + return 1; +} static uint16_t get_short(const unsigned char *s) @@ -21,7 +33,7 @@ push(uint16_t v) stack_ptr += 1; if (stack_ptr >= MEM_SIZE) { fprintf(stderr, "stack overflow\n"); - return; + exit(fail()); } } @@ -30,16 +42,38 @@ pop(void) { if (stack_ptr == 0) { fprintf(stderr, "stack underflow\n"); - return 0; + exit(fail()); } stack_ptr -= 1; return stack[stack_ptr]; } + +static void +push_rs(uint16_t v) +{ + rstack[rstack_ptr] = v; + rstack_ptr += 1; + if (rstack_ptr >= MEM_SIZE) { + fprintf(stderr, "return stack overflow\n"); + exit(fail()); + } +} +static uint16_t +pop_rs(void) +{ + if (rstack_ptr == 0) { + fprintf(stderr, "return stack underflow\n"); + exit(fail()); + } + rstack_ptr -= 1; + return rstack[rstack_ptr]; +} + static void exec_data(uint16_t *mem) { - for (long pc = 0; pc < MEM_SIZE; pc++) { + for (long pc = 0; pc < MEM_SIZE;) { switch (mem[pc]) { case OP_NOP: break; @@ -47,15 +81,63 @@ exec_data(uint16_t *mem) push(mem[pc + 1]); pc += 1; break; + case OP_POP: + pop(); + break; + case OP_NIP: { + const uint16_t a = pop(); + pop(); + push(a); + } break; + case OP_SWP: { + const uint16_t a = pop(); + const uint16_t b = pop(); + push(a); + push(b); + } break; + case OP_DUP: { + const uint16_t a = pop(); + push(a); + push(a); + } break; + case OP_ADD: + push(pop() + pop()); + break; case OP_WRT: putchar(pop()); break; + case OP_JNZ: + if (pop() != 0) { + pc = mem[pc + 1]; + continue; + } + pc += 1; + break; + case OP_JRT: + push_rs(pc); + pc = mem[pc + 1]; + continue; case OP_RET: + if (rstack_ptr > 0) { + pc = pop_rs() + 1; + break; + } return; + case OP_LDA: + push(mem[pop()]); + break; + case OP_STA: { + const uint16_t a = pop(); + const uint16_t b = pop(); + mem[a] = b; + } break; default: fprintf(stderr, "unhandled opcode %04x\n", mem[pc]); - return; + if (mem[pc] <= OP_SLP) + fprintf(stderr, "(%s)\n", ops[mem[pc]]); + exit(fail()); } + pc += 1; } } @@ -79,7 +161,7 @@ main(int argc, char **argv) if (data == NULL) return 1; - uint16_t *mem = calloc(MEM_SIZE, sizeof(uint16_t)); + mem = calloc(MEM_SIZE, sizeof(uint16_t)); if (mem == NULL) { perror("main:calloc"); free(data); @@ -93,12 +175,15 @@ main(int argc, char **argv) stack = calloc(MEM_SIZE, sizeof(uint16_t)); if (stack == NULL) { perror("main:calloc"); - free(mem); - return 1; + return fail(); + } + + rstack = calloc(MEM_SIZE, sizeof(uint16_t)); + if (rstack == NULL) { + perror("main:calloc"); + return fail(); } exec_data(mem); - free(mem); - free(stack); - return 0; + return fail(), 0; } |