Added ability to record a JMP/BRZ trace in nedsim, with labels where applicable.
authorAaron Taylor <ataylor@subgeniuskitty.com>
Mon, 31 Dec 2018 10:59:05 +0000 (02:59 -0800)
committerAaron Taylor <ataylor@subgeniuskitty.com>
Mon, 31 Dec 2018 10:59:05 +0000 (02:59 -0800)
docs/compat_matrix.md
nedsim/nedsim.c

index 75bfe4c..eb6cb94 100644 (file)
@@ -11,3 +11,4 @@ Compatibility Matrix
 | ------ | ------ | ------ | ---------- | ---------- |
 |      1 |      1 |      1 |          1 |          1 |
 |      2 |      2 |      2 |          . |          . |
 | ------ | ------ | ------ | ---------- | ---------- |
 |      1 |      1 |      1 |          1 |          1 |
 |      2 |      2 |      2 |          . |          . |
+|      3 |      . |      . |          . |          . |
index 9d5a045..aa9b7c4 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "../common/a.out.h"
 
 
 #include "../common/a.out.h"
 
-#define VERSION 2
+#define VERSION 3
 
 /* Bytes per word. */
 #define BPW 4
 
 /* Bytes per word. */
 #define BPW 4
@@ -99,6 +99,7 @@ print_usage(char ** argv)
             "  -i <file>               Specify a binary image file to load in RAM.\n"
             "  -p <int ns, optional>   Period in nanoseconds of simulated system clock.\n"
             "                          Allowable values are 1 <= clock <= 1,000,000,000.\n"
             "  -i <file>               Specify a binary image file to load in RAM.\n"
             "  -p <int ns, optional>   Period in nanoseconds of simulated system clock.\n"
             "                          Allowable values are 1 <= clock <= 1,000,000,000.\n"
+            "  -t <file>               Saves a trace of JMP and BRZ syllables to file.\n"
             , VERSION, argv[0]
     );
 }
             , VERSION, argv[0]
     );
 }
@@ -544,7 +545,8 @@ wait_for_next_clock_cycle(struct NEDstate * state)
 }
 
 void
 }
 
 void
-parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment)
+parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment,
+                struct nlist ** symbol_table, uint32_t * symbol_count)
 {
     uint32_t read_count = 0;
 
 {
     uint32_t read_count = 0;
 
@@ -587,6 +589,48 @@ parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment)
         for (uint8_t j=0; j<4; j++) temp_word[j] = text_segment[((i*4)+j)];
         for (uint8_t j=0; j<4; j++) text_segment[((i*4)+j)] = temp_word[(3-j)];
     }
         for (uint8_t j=0; j<4; j++) temp_word[j] = text_segment[((i*4)+j)];
         for (uint8_t j=0; j<4; j++) text_segment[((i*4)+j)] = temp_word[(3-j)];
     }
+
+    /* Read in the symbol table. */
+    *symbol_count = ((N_STROFF(*aout_exec) - N_SYMOFF(*aout_exec)) / 20); /* 20 bytes per symbol. */
+    *symbol_table = malloc((*symbol_count) * sizeof(struct nlist));
+    for (uint32_t i=0; i < *symbol_count; i++) {
+        for (uint32_t j=0; j<5; j++) {
+            switch (j) {
+                case 0: read_count = fread(&((*symbol_table)[i].n_un.n_strx), 4, 1, input); break;
+                case 1: read_count = fread(&((*symbol_table)[i].n_type),      4, 1, input); break;
+                case 2: read_count = fread(&((*symbol_table)[i].n_other),     4, 1, input); break;
+                case 3: read_count = fread(&((*symbol_table)[i].n_desc),      4, 1, input); break;
+                case 4: read_count = fread(&((*symbol_table)[i].n_value),     4, 1, input); break;
+            }
+            if (read_count != 1) {
+                fprintf(stderr, "ERROR: Unable to read entire symbol table.\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+    /* Read in the string table and update the symbol table entries with pointers to new strings. */
+    uint32_t string_table_size;
+    read_count = fread(&string_table_size, 4, 1, input);
+    if (read_count != 1) {
+        fprintf(stderr, "ERROR: Failed to read string table size.\n");
+        exit(EXIT_FAILURE);
+    }
+    for (uint32_t i=0; i < *symbol_count; i++) {
+        uint32_t len = 0;
+        if (i < ((*symbol_count)-1)) {
+            len = ((*symbol_table)[i+1].n_un.n_strx - (*symbol_table)[i].n_un.n_strx);
+        } else {
+            len = (string_table_size - (*symbol_table)[i].n_un.n_strx);
+        }
+        (*symbol_table)[i].n_un.n_name = malloc(len);
+        read_count = fread((*symbol_table)[i].n_un.n_name, 1, len, input);
+        if (read_count != len) {
+            fprintf(stderr, "ERROR: Failed to read a string from the string table.\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
 }
 
 
 }
 
 
@@ -598,9 +642,16 @@ main(int argc, char ** argv)
      */
     int c;
     FILE * input = NULL;
      */
     int c;
     FILE * input = NULL;
+    FILE * trace = NULL;
     uint32_t clock_period = 1;
     uint32_t clock_period = 1;
-    while ((c = getopt(argc,argv,"i:p:h")) != -1) {
+    while ((c = getopt(argc,argv,"i:p:t:h")) != -1) {
         switch (c) {
         switch (c) {
+            case 't':
+                if ((trace = fopen(optarg, "wx")) == NULL) {
+                    fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
+                    exit(EXIT_FAILURE);
+                }
+                break;
             case 'i':
                 if ((input = fopen(optarg, "r")) == NULL) {
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
             case 'i':
                 if ((input = fopen(optarg, "r")) == NULL) {
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
@@ -655,13 +706,16 @@ main(int argc, char ** argv)
     /* Load an initial image into memory. */
     uint32_t address = 0x20000000;
     struct exec aout_exec;
     /* Load an initial image into memory. */
     uint32_t address = 0x20000000;
     struct exec aout_exec;
-    parse_aout_file(input, &aout_exec, &(state->ram[address]));
+    struct nlist * symbol_table;
+    uint32_t symbol_count;
+    parse_aout_file(input, &aout_exec, &(state->ram[address]), &symbol_table, &symbol_count);
     fclose(input);
 
     /*
      * Main Loop
      */
     uint32_t iw = 0;
     fclose(input);
 
     /*
      * Main Loop
      */
     uint32_t iw = 0;
+    uint32_t next_pc = 0;
     while (1) {
         /* Check for interrupt requests. */
         /* TODO */
     while (1) {
         /* Check for interrupt requests. */
         /* TODO */
@@ -669,6 +723,41 @@ main(int argc, char ** argv)
         /* Fetch new instruction word. */
         iw = fetch_instruction_word(state);
 
         /* Fetch new instruction word. */
         iw = fetch_instruction_word(state);
 
+        /* Tracing, if enabled. */
+        if (trace) {
+            if (next_pc == 0) next_pc = state->active_thread->pc;
+            if (next_pc != (state->active_thread->pc - BPW)) {
+                /* A jump has occurred. */
+                char * trace_msg = NULL;
+                asprintf(&trace_msg, "Jump from 0x%08x to 0x%08x ",
+                        (next_pc - BPW), (state->active_thread->pc - BPW)
+                    );
+                if (trace_msg != NULL) {
+                    fwrite(trace_msg, strlen(trace_msg), 1, trace);
+                    free(trace_msg);
+                }
+
+                trace_msg = NULL;
+                char * symbol_string = NULL;
+                for (uint32_t i=0; i < symbol_count; i++) {
+                    if ((state->active_thread->pc - BPW) == symbol_table[i].n_value) {
+                        symbol_string = symbol_table[i].n_un.n_name;
+                        break;
+                    }
+                }
+                if (symbol_string) {
+                    asprintf(&trace_msg, "(%s).\n", symbol_string);
+                    if (trace_msg != NULL) {
+                        fwrite(trace_msg, strlen(trace_msg), 1, trace);
+                        free(trace_msg);
+                    }
+                } else {
+                    fwrite("\n", 1, 1, trace);
+                }
+            } 
+            next_pc = state->active_thread->pc;
+        }
+
         /* Decode instruction word format and execute. */
         if (iw & (0b1 << 31)) {                /* Instruction word is type A. */
             wait_for_next_clock_cycle(state);
         /* Decode instruction word format and execute. */
         if (iw & (0b1 << 31)) {                /* Instruction word is type A. */
             wait_for_next_clock_cycle(state);