Added missing newline in NEDsim error message.
[screensavers] / hacks / NEDsim / simulator.c
index 9c63b67..b433e0d 100644 (file)
@@ -7,21 +7,10 @@
 
 #include <stdio.h>
 #include <stdint.h>
 
 #include <stdio.h>
 #include <stdint.h>
-#include <inttypes.h>
 #include <stdlib.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdbool.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <string.h>
 #include <errno.h>
 #include <string.h>
 #include <errno.h>
-#include <time.h>
-#include <termios.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 
 #include "a.out.h"
 #include "simulator.h"
 
 #include "a.out.h"
 #include "simulator.h"
@@ -172,9 +161,6 @@ ned_instruction_add(struct NEDstate * state)
 static void
 ned_instruction_shift(struct NEDstate * state)
 {
 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) {
     uint32_t shift_by = stack_pop(state->active_thread);
     uint32_t word = stack_pop(state->active_thread);
     if (shift_by & 0x80000000) {
@@ -378,7 +364,7 @@ parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment,
 }
 
 struct NEDstate *
 }
 
 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));
 {
     struct NEDstate * state = malloc(sizeof(struct NEDstate));
     state->hack = malloc(sizeof(struct NEDhack));
@@ -395,20 +381,39 @@ init_simulator(char * input_file)
     state->hack->resume_word = false;
 
     /* Load an initial image into memory. */
     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;
     }
         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;
 }
 
     return state;
 }
@@ -422,8 +427,10 @@ run_simulator(struct NEDstate * state)
     uint32_t iw;
     if (state->hack->resume_word) {
         iw = state->hack->iw;
     uint32_t iw;
     if (state->hack->resume_word) {
         iw = state->hack->iw;
+        state->active_thread->sc++;
     } else {
         iw = fetch_instruction_word(state);
     } else {
         iw = fetch_instruction_word(state);
+        state->active_thread->sc = 0;
     }
 
     /* Decode instruction word format and execute. */
     }
 
     /* Decode instruction word format and execute. */
@@ -431,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);
         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) {
         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;
             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 {
             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;
         }
             state->hack->resume_word = true;
             state->hack->iw = iw;
         }