#include "../common/a.out.h"
-#define VERSION 2
+#define VERSION 3
/* Bytes per word. */
#define BPW 4
" -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]
);
}
}
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;
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);
+ }
+ }
+
}
*/
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));
/* 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 */
/* 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);