X-Git-Url: http://git.subgeniuskitty.com/screensavers/.git/blobdiff_plain/5923644e9538d96dfdcaba6f76b3f9f903da071c..HEAD:/hacks/NEDsim/simulator.c diff --git a/hacks/NEDsim/simulator.c b/hacks/NEDsim/simulator.c index 9708486..b433e0d 100644 --- a/hacks/NEDsim/simulator.c +++ b/hacks/NEDsim/simulator.c @@ -5,29 +5,17 @@ /* NED1 Simulator */ /* -------------------------------------------------------------------------- */ -// TODO: Make a bunch of functions private in this file. #include #include -#include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include "a.out.h" #include "simulator.h" -uint32_t +static uint32_t generate_binary_psw(struct NEDstate * state) { uint32_t psw = 0; @@ -36,13 +24,13 @@ generate_binary_psw(struct NEDstate * state) return psw; } -void +static void ram_w_byte(struct NEDstate * state, uint32_t address, uint8_t data) { state->ram[address-RAM_BASE_ADDRESS] = data; } -uint8_t +static uint8_t ram_r_byte(struct NEDstate * state, uint32_t address) { return state->ram[address-RAM_BASE_ADDRESS]; @@ -50,7 +38,7 @@ ram_r_byte(struct NEDstate * state, uint32_t address) /* For now, with only a terminal for IO, we pick off IO requests when accessing RAM. */ -void +static void ram_w_word(struct NEDstate * state, uint32_t address, uint32_t data) { if (address >= RAM_BASE_ADDRESS) { @@ -80,7 +68,7 @@ ram_r_word(struct NEDstate * state, uint32_t address) return 0b0; } -uint32_t +static uint32_t fetch_instruction_word(struct NEDstate * state) { uint32_t word = ram_r_word(state, state->active_thread->pc); @@ -88,31 +76,31 @@ fetch_instruction_word(struct NEDstate * state) return word; } -void +static void stack_w(struct NEDthread * thread, uint32_t value, uint8_t offset) { thread->stack[thread->sp - (offset + 1)] = value; } -uint32_t +static uint32_t stack_r(struct NEDthread * thread, uint8_t offset) { return thread->stack[thread->sp - (offset + 1)]; } -void +static void stack_push(struct NEDthread * thread, uint32_t value) { thread->stack[thread->sp++] = value; } -uint32_t +static uint32_t stack_pop(struct NEDthread * thread) { return thread->stack[--thread->sp]; } -void +static void set_psw_flags(uint32_t word, struct NEDstate * state) { if (word == 0) { @@ -127,7 +115,7 @@ set_psw_flags(uint32_t word, struct NEDstate * state) } } -void +static void ned_instruction_and(struct NEDstate * state) { uint32_t operand1 = stack_pop(state->active_thread); @@ -136,7 +124,7 @@ ned_instruction_and(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_or(struct NEDstate * state) { uint32_t operand1 = stack_pop(state->active_thread); @@ -145,14 +133,14 @@ ned_instruction_or(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_not(struct NEDstate * state) { stack_push(state->active_thread, ~stack_pop(state->active_thread)); set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_xor(struct NEDstate * state) { uint32_t operand1 = stack_pop(state->active_thread); @@ -161,7 +149,7 @@ ned_instruction_xor(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_add(struct NEDstate * state) { uint32_t operand1 = stack_pop(state->active_thread); @@ -170,12 +158,9 @@ ned_instruction_add(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_shift(struct NEDstate * state) { - /* TODO: Bounds check: Either all inputs are valid OR shift_by < 32. */ - /* I guess this also depends if I'm shifting-and-dropping, or barrel-shifting. */ - /* How should I pad for a right shift if I shift-and-drop? Sign extend? */ uint32_t shift_by = stack_pop(state->active_thread); uint32_t word = stack_pop(state->active_thread); if (shift_by & 0x80000000) { @@ -186,21 +171,21 @@ ned_instruction_shift(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_test(struct NEDstate * state) { uint32_t word = stack_pop(state->active_thread); set_psw_flags(word, state); } -void +static void ned_instruction_jmp(struct NEDstate * state) { state->active_thread->pc = stack_pop(state->active_thread); // The SC is caught and reset by the main loop since the PC changed. } -void +static void ned_instruction_swap(struct NEDstate * state) { uint32_t temp1 = stack_pop(state->active_thread); @@ -210,7 +195,7 @@ ned_instruction_swap(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_brz(struct NEDstate * state) { uint32_t new_pc = stack_pop(state->active_thread); @@ -221,7 +206,7 @@ ned_instruction_brz(struct NEDstate * state) } } -void +static void ned_instruction_load(struct NEDstate * state) { uint32_t address = stack_pop(state->active_thread); @@ -229,7 +214,7 @@ ned_instruction_load(struct NEDstate * state) set_psw_flags(stack_r(state->active_thread,0), state); } -void +static void ned_instruction_store(struct NEDstate * state) { uint32_t address = stack_pop(state->active_thread); @@ -237,14 +222,14 @@ ned_instruction_store(struct NEDstate * state) ram_w_word(state, address, data); } -void +static void ned_instruction_halt(struct NEDstate * state) { printf("Halting.\n"); state->halted = true; } -void +static void execute_syllable(struct NEDstate * state, enum syllables syllable) { if (syllable & 0b100000) { /* Check the first bit of the syllable. 1 means IM_x. */ @@ -282,14 +267,14 @@ execute_syllable(struct NEDstate * state, enum syllables syllable) } } -uint8_t +static uint8_t extract_syllable_from_word(uint32_t word, uint8_t index) { uint32_t mask = 0b111111 << 6*(4-index); return (word & mask) >> 6*(4-index); } -void +static void parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment, struct nlist ** symbol_table, uint32_t * symbol_count) { @@ -379,7 +364,7 @@ parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment, } struct NEDstate * -init_simulator(char * input_file) +init_simulator(char * input_file, const uint8_t * blob, const size_t * blob_size) { struct NEDstate * state = malloc(sizeof(struct NEDstate)); state->hack = malloc(sizeof(struct NEDhack)); @@ -396,20 +381,39 @@ init_simulator(char * input_file) state->hack->resume_word = false; /* Load an initial image into memory. */ - struct exec aout_exec; - struct nlist * symbol_table; - uint32_t symbol_count; - FILE * input = NULL; - if ((input = fopen(input_file, "r")) == NULL) { - fprintf(stderr, "ERROR: %s: %s\n", input_file, strerror(errno)); + if (input_file) { + struct exec aout_exec; + struct nlist * symbol_table; + uint32_t symbol_count; + FILE * input = NULL; + if ((input = fopen(input_file, "r")) == NULL) { + fprintf(stderr, "ERROR: %s: %s\n", input_file, strerror(errno)); + state->halted = true; + } + parse_aout_file(input, &aout_exec, state->ram, &symbol_table, &symbol_count); + fclose(input); + for (size_t i=0; i < symbol_count; i++) { + free(symbol_table[i].n_un.n_name); + } + free(symbol_table); + } else if (blob && blob_size) { + if (*blob_size <= RAM_LENGTH) { + size_t index = *blob_size; + while (index) { + index--; + state->ram[index] = blob[index]; + } + } else { + fprintf(stderr, + "ERROR: Built-in NED1 program is larger than simulated RAM (%zu vs %d bytes)\n", + *blob_size, RAM_LENGTH + ); + state->halted = true; + } + } else { + fprintf(stderr, "ERROR: No suitable binary image passed when initializing simulator.\n"); state->halted = true; } - parse_aout_file(input, &aout_exec, state->ram, &symbol_table, &symbol_count); - fclose(input); - for (size_t i=0; i < symbol_count; i++) { - free(symbol_table[i].n_un.n_name); - } - free(symbol_table); return state; } @@ -423,8 +427,10 @@ run_simulator(struct NEDstate * state) uint32_t iw; if (state->hack->resume_word) { iw = state->hack->iw; + state->active_thread->sc++; } else { iw = fetch_instruction_word(state); + state->active_thread->sc = 0; } /* Decode instruction word format and execute. */ @@ -432,19 +438,18 @@ run_simulator(struct NEDstate * state) stack_push(state->active_thread, (iw << 1)); } else if ((iw & (0b11 << 30)) == 0) { /* Instruction word is type C. */ uint8_t syllable = extract_syllable_from_word(iw, state->active_thread->sc); - state->active_thread->sc++; // TODO: Should this be part of extract_syllable_from_word()? After all, incrementing the PC is done in fetch_instruction_word(). - uint32_t pre_execution_pc = state->active_thread->pc; // TODO: This is so we can catch JMP/JSR/etc subroutines that need the SC to be reset to zero. + /* The following variable allows us to catch JMP/BRZ instructions that */ + /* jump to a new PC and need the SC reset. */ + uint32_t pre_execution_pc = state->active_thread->pc; execute_syllable(state, syllable); if (state->active_thread->pc != pre_execution_pc) { - // Jumped to a new address, so prepare to execute a new instruction word. - state->active_thread->sc = 0; + /* Jumped to a new address, so prepare to execute a new instruction word. */ state->hack->resume_word = false; - } else if (state->active_thread->sc >= SPW) { - // Just executed the last syllable in this word, time to follow the PC to the next word. - state->active_thread->sc = 0; + } else if (state->active_thread->sc >= SPW-1) { + /* Just executed the last syllable in this word, follow the PC to the next word. */ state->hack->resume_word = false; } else { - // More syllables remain to be executed in this instruction word. + /* More syllables remain to be executed in this instruction word. */ state->hack->resume_word = true; state->hack->iw = iw; }