-
-
Save itsbth/1379332 to your computer and use it in GitHub Desktop.
Uploaded by UploadToGist for Sublime Text 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "vm.h" | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <stdbool.h> | |
| #include <assert.h> | |
| struct _vm_state { | |
| int regi[8]; | |
| double regf[8]; | |
| unsigned int code_len; | |
| unsigned int *code; | |
| unsigned int data_len; | |
| int *data; | |
| unsigned int iptr; | |
| unsigned int sptr; | |
| vm_interrupt_handler interrupt_table[VM_INTERRUPT_TABLE_SIZE]; | |
| }; | |
| #include "instr_names.c" | |
| void *vm_decode_rm(vm_state s, unsigned int rm, bool write); | |
| void print_rm(char *target, unsigned int rm) { | |
| unsigned int val = rm & VM_DATA_MASK; | |
| char tmp[64]; | |
| if (rm & VM_REG_MASK) { | |
| sprintf(tmp, "VM_REG(0x%x)", val); | |
| } else if (rm & VM_CODE_MASK) { | |
| sprintf(tmp, "VM_CODE(0x%x)", val); | |
| } else { | |
| sprintf(tmp, "0x%x", val); | |
| } | |
| strcat(target, tmp); | |
| } | |
| char *print_instr(vm_state s, unsigned int iptr) { | |
| static char line[256]; | |
| memset(line, 0, 256); | |
| strcat(line, instr_names[s->code[iptr]]); | |
| strcat(line, " "); | |
| print_rm(line, s->code[iptr+1]); | |
| strcat(line, ", "); | |
| print_rm(line, s->code[iptr+2]); | |
| return line; | |
| } | |
| void _panic(vm_state s, bool pred, char *pred_str, char *file, int line) { | |
| if (pred) return; | |
| fprintf(stderr, "ASSERTION FAILED:\n"); | |
| fprintf(stderr, " `%s`\n", pred_str); | |
| fprintf(stderr, " in %s:%d\n", file, line); | |
| fprintf(stderr, " ---\n"); | |
| fprintf(stderr, " s->iptr = 0x%x\n", s->iptr); | |
| fprintf(stderr, " ---\n"); | |
| if (s->iptr >= 3) fprintf(stderr, " %s\n", print_instr(s, s->iptr-3)); | |
| fprintf(stderr, "->%s<-\n", print_instr(s, s->iptr)); | |
| if (s->iptr+3 < s->code_len) fprintf(stderr, " %s\n", print_instr(s, s->iptr+3)); | |
| exit(1); | |
| } | |
| #define panic(state, pred) _panic(state, pred, #pred, __FILE__, __LINE__) | |
| vm_state vm_create_state(unsigned int *code, unsigned int code_len, unsigned int data_len) { | |
| vm_state s = malloc(sizeof(struct _vm_state)); | |
| memset(s, 0, sizeof(struct _vm_state)); | |
| s->code = code; // TODO: Create a copy? | |
| s->code_len = code_len; | |
| s->data_len = data_len; | |
| s->data = malloc(sizeof(int) * data_len); | |
| s->iptr = 0; | |
| return s; | |
| } | |
| void *vm_decode_rm(vm_state s, unsigned int rm, bool write) { | |
| unsigned int data_val = rm & VM_DATA_MASK; | |
| if (rm & VM_REG_MASK) { | |
| panic(s, data_val < 16); | |
| return &s->regi[data_val]; | |
| } | |
| if (rm & VM_CODE_MASK) { | |
| panic(s, data_val < s->code_len); | |
| return &s->code[data_val]; | |
| } | |
| //if (rm & VM_CONST_MASK && !write) { | |
| // return | |
| //} | |
| panic(s, data_val < s->data_len); | |
| return s->data + data_val; | |
| } | |
| int vm_get_int(vm_state s, unsigned int ptr) { | |
| int *ret = vm_decode_rm(s, ptr, false); | |
| return *ret; | |
| } | |
| void vm_set_int(vm_state s, unsigned int ptr, int val) { | |
| int *ret = vm_decode_rm(s, ptr, true); | |
| *ret = val; | |
| } | |
| double vm_get_double(vm_state s, unsigned int ptr) { | |
| double *ret = vm_decode_rm(s, ptr, false); | |
| return *ret; | |
| } | |
| void vm_set_double(vm_state s, unsigned int ptr, double val) { | |
| double *ret = vm_decode_rm(s, ptr, false); | |
| *ret = val; | |
| } | |
| bool vm_set_data(vm_state s, unsigned int ptr, char *data, unsigned int data_len) { | |
| if (ptr + data_len > s->data_len) | |
| return false; | |
| memcpy(s->data + ptr, data, data_len); | |
| return true; | |
| } | |
| unsigned int vm_get_data(vm_state s, unsigned int ptr, char *dest, unsigned int dest_len) { | |
| if(ptr + dest_len > s->data_len) | |
| dest_len = s->data_len - ptr; | |
| memcpy(dest, s->data + ptr, dest_len); | |
| return dest_len; | |
| } | |
| void vm_register_interrupt(vm_state s, unsigned int itr, vm_interrupt_handler handler) { | |
| panic(s, itr < VM_INTERRUPT_TABLE_SIZE && handler != NULL); | |
| s->interrupt_table[itr] = handler; | |
| } | |
| void vm_run_interrupt(vm_state s, unsigned int itr) { | |
| fprintf(stderr, "Interrupt: %x\n", itr); | |
| panic(s, itr < VM_INTERRUPT_TABLE_SIZE && s->interrupt_table[itr] != NULL); | |
| s->interrupt_table[itr](s); | |
| } | |
| void vm_run_instruction(vm_state s) { | |
| unsigned int instr = s->code[s->iptr], | |
| *rm1 = vm_decode_rm(s, s->code[s->iptr+1], false), | |
| *rm2 = vm_decode_rm(s, s->code[s->iptr+2], false); | |
| //#ifdef VERBOSE | |
| fprintf(stderr, "%x: %s [%u, %u]\n", s->iptr, print_instr(s, s->iptr), *rm1, *rm2); | |
| //#endif // VERBOSE | |
| switch (instr) { | |
| case INSTR_NOP: | |
| break; | |
| case INSTR_INT: | |
| vm_run_interrupt(s, *rm1); | |
| break; | |
| case INSTR_MOV: | |
| *rm1 = *rm2; | |
| break; | |
| case INSTR_ADDI: | |
| *rm1 = *rm1 + *rm2; | |
| break; | |
| default: | |
| panic(s, true && "unknown opcode"); | |
| } | |
| s->iptr += 3; | |
| //NO_INCR: | |
| return; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment