From: Aaron Taylor Date: Mon, 31 Dec 2018 10:59:05 +0000 (-0800) Subject: Added ability to record a JMP/BRZ trace in nedsim, with labels where applicable. X-Git-Url: http://git.subgeniuskitty.com/ned1/.git/commitdiff_plain/91c220b6831b5fb24d4f8945004b83a08fb3abe1 Added ability to record a JMP/BRZ trace in nedsim, with labels where applicable. --- diff --git a/docs/compat_matrix.md b/docs/compat_matrix.md index 75bfe4c..eb6cb94 100644 --- a/docs/compat_matrix.md +++ b/docs/compat_matrix.md @@ -11,3 +11,4 @@ Compatibility Matrix | ------ | ------ | ------ | ---------- | ---------- | | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 2 | . | . | +| 3 | . | . | . | . | diff --git a/nedsim/nedsim.c b/nedsim/nedsim.c index 9d5a045..aa9b7c4 100644 --- a/nedsim/nedsim.c +++ b/nedsim/nedsim.c @@ -18,7 +18,7 @@ #include "../common/a.out.h" -#define VERSION 2 +#define VERSION 3 /* Bytes per word. */ #define BPW 4 @@ -99,6 +99,7 @@ print_usage(char ** argv) " -i Specify a binary image file to load in RAM.\n" " -p Period in nanoseconds of simulated system clock.\n" " Allowable values are 1 <= clock <= 1,000,000,000.\n" + " -t Saves a trace of JMP and BRZ syllables to file.\n" , VERSION, argv[0] ); } @@ -544,7 +545,8 @@ wait_for_next_clock_cycle(struct NEDstate * state) } 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; @@ -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)]; } + + /* 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; + FILE * trace = NULL; 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) { + 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)); @@ -655,13 +706,16 @@ main(int argc, char ** argv) /* 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; + uint32_t next_pc = 0; 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); + /* 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);