X-Git-Url: http://git.subgeniuskitty.com/ned1/.git/blobdiff_plain/bc5b63cf94c1f263bbe3757237b242f40711203b..HEAD:/nedsim/nedsim.c diff --git a/nedsim/nedsim.c b/nedsim/nedsim.c index 9bdaa59..b443fc2 100644 --- a/nedsim/nedsim.c +++ b/nedsim/nedsim.c @@ -15,8 +15,15 @@ #include #include #include +#include +#include +#include +#include +#include -#define VERSION 1 +#include "../common/a.out.h" + +#define VERSION 5 /* Bytes per word. */ #define BPW 4 @@ -92,11 +99,14 @@ void print_usage(char ** argv) { printf( "NED Simulator v%d (www.subgeniuskitty.com)\n" - "Usage: %s -i \n" + "Usage: %s -i [-s } [-t ] [-a
-p ]\n" " -h Help (prints this message)\n" " -i Specify a binary image file to load in RAM.\n" - " -p Period in nanoseconds of simulated system clock.\n" + " -s Frequency 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" + " -a IP address of nedfp instance. Enables front panel output.\n" + " -p Port of nedfp instance. Required when '-i' specified.\n" , VERSION, argv[0] ); } @@ -434,7 +444,8 @@ void ned_instruction_brz(struct NEDstate * state) { uint32_t new_pc = stack_pop(state->active_thread); - if (state->active_thread->psw->zero == true) { + uint32_t test_word = stack_pop(state->active_thread); + if (test_word == 0) { state->active_thread->pc = new_pc; /* TODO: Find better way to communicate we're skipping ahead to the next word. */ state->active_thread->sc = 4; @@ -541,6 +552,143 @@ wait_for_next_clock_cycle(struct NEDstate * state) } } +void +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; + + /* Read in and check the a.out header. */ + for (uint32_t i=0; i<8; i++) { + switch (i) { + case 0: read_count = fread(&(aout_exec->a_midmag), 4, 1, input); break; + case 1: read_count = fread(&(aout_exec->a_text), 4, 1, input); break; + case 2: read_count = fread(&(aout_exec->a_data), 4, 1, input); break; + case 3: read_count = fread(&(aout_exec->a_bss), 4, 1, input); break; + case 4: read_count = fread(&(aout_exec->a_syms), 4, 1, input); break; + case 5: read_count = fread(&(aout_exec->a_entry), 4, 1, input); break; + case 6: read_count = fread(&(aout_exec->a_trsize), 4, 1, input); break; + case 7: read_count = fread(&(aout_exec->a_drsize), 4, 1, input); break; + } + if (read_count != 1) { + fprintf(stderr, "ERROR: Invalid a.out header.\n"); + exit(EXIT_FAILURE); + } + } + if (N_BADMAG(*aout_exec)) { + fprintf(stderr, "ERROR: Invalid magic number in a.out header.\n"); + exit(EXIT_FAILURE); + } else if (N_GETMID(*aout_exec) != MID_NED) { + fprintf(stderr, "ERROR: Executable not intended for NED Machine ID.\n"); + exit(EXIT_FAILURE); + } + + /* Read in the text segment. */ + uint32_t text_segment_size = (N_DATOFF(*aout_exec) - N_TXTOFF(*aout_exec)); + read_count = fread(text_segment, 1, text_segment_size, input); + if (read_count != text_segment_size) { + fprintf(stderr, "ERROR: Failed to read entire text segment.\n"); + exit(EXIT_FAILURE); + } + + /* Correct the byte order. */ + for (uint32_t i=0; i < (text_segment_size / 4); i++) { + uint8_t temp_word[4]; + 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); + } + } + +} + +void +send_front_panel_update(struct NEDstate * state, int sockfd, uint32_t ram_address, + const struct sockaddr *to, socklen_t tolen) +{ + /* + * Datagram format (all entries are 4 bytes): + * Sequence number (See RFC1982) + * Currently executing word + * PC + * SC + * PSW + * SP + * Top 16 stack entries + * RAM start address + * Top 16 RAM words from start address + */ + uint32_t snapshot[39]; + + static uint32_t seq_num; + seq_num == 0xffffffff ? seq_num = 0 : seq_num++; + snapshot[0] = seq_num; + + snapshot[1] = ram_r_word(state, (state->active_thread->pc - 4)); + snapshot[2] = state->active_thread->pc; + snapshot[3] = (uint32_t) state->active_thread->sc; + snapshot[4] = generate_binary_psw(state); + snapshot[5] = state->active_thread->sp; + + int64_t sp = state->active_thread->sp; + for (int i=0; i<16; i++) { + if ((sp-i) < 0) { + snapshot[i+6] = 0; + } else { + snapshot[i+6] = state->active_thread->stack[sp-i]; + } + } + + snapshot[22] = ram_address; + for (int i=0; i<16; i++) { + snapshot[i+23] = ram_r_word(state,(ram_address + (i * 4))); + } + + int numbytes; + if ((numbytes = sendto(sockfd, snapshot, 156, 0, to, tolen)) == -1) { + fprintf(stderr, "WARNING: Unable to send machine snapshot to front panel socket.\n"); + } +} + int main(int argc, char ** argv) { @@ -549,21 +697,40 @@ 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) { + char * fp_ip = NULL; + char * fp_port = NULL; + uint32_t fp_ram = 0x40000000; + while ((c = getopt(argc,argv,"hi:p:t:s:a:")) != -1) { switch (c) { case 'i': if ((input = fopen(optarg, "r")) == NULL) { fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno)); + exit(EXIT_FAILURE); + } + break; + case 't': + if ((trace = fopen(optarg, "wx")) == NULL) { + fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno)); + exit(EXIT_FAILURE); } break; + case 'a': + // TODO: What do I want to consider valid input? + fp_ip = optarg; + break; case 'p': + // TODO: What do I want to consider valid input? + fp_port = optarg; + break; + case 's': { - intmax_t temp_p = strtoimax(optarg, NULL, 0); - if (1 <= temp_p && temp_p <= 1000000000) { - clock_period = temp_p; + intmax_t freq = strtoimax(optarg, NULL, 0); + if (1 <= freq && freq <= 1000000000) { + clock_period = ((1.0 / freq) * 1000000000); } else { - fprintf(stderr, "ERROR: Clock period out of range.\n"); + fprintf(stderr, "WARNING: Clock period out of range.\n"); } break; } @@ -580,6 +747,7 @@ main(int argc, char ** argv) print_usage(argv); exit(EXIT_FAILURE); } + if (fp_ip != NULL && fp_port == NULL) asprintf(&fp_port, "4999"); /* * Initialization @@ -603,18 +771,49 @@ main(int argc, char ** argv) signal(SIGINT, ned_sigint_handler); /* Load an initial image into memory. */ - uint32_t temp_word; uint32_t address = 0x20000000; - while(fread(&temp_word, 4, 1, input)) { - ram_w_word(state, address, temp_word); - address += 4; - } + struct exec aout_exec; + struct nlist * symbol_table; + uint32_t symbol_count; + parse_aout_file(input, &aout_exec, &(state->ram[address]), &symbol_table, &symbol_count); fclose(input); + /* Start up the front panel connections, if specified. */ + int sockfd; + struct addrinfo * p; + if (fp_ip) { + struct addrinfo hints; + struct addrinfo * servinfo; + int rv; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + if ((rv = getaddrinfo(fp_ip, fp_port, &hints, &servinfo)) != 0) { + fprintf(stderr, "ERROR: getaddrinfo: %s\n", gai_strerror(rv)); + exit(EXIT_FAILURE); + } + + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + continue; + } + break; + } + + if (p == NULL) { + fprintf(stderr, "ERROR: Failed to create socket\n"); + exit(EXIT_FAILURE); + } + freeaddrinfo(servinfo); + } + /* * Main Loop */ uint32_t iw = 0; + uint32_t next_pc = 0; while (1) { /* Check for interrupt requests. */ /* TODO */ @@ -622,8 +821,44 @@ 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. */ + if (fp_ip) send_front_panel_update(state, sockfd, fp_ram, p->ai_addr, p->ai_addrlen); wait_for_next_clock_cycle(state); stack_push(state->active_thread, (iw << 1)); state->active_thread->debug->cycle_count += 1; @@ -632,6 +867,7 @@ main(int argc, char ** argv) state->active_thread->sc < SPW; state->active_thread->sc++ ) { + if (fp_ip) send_front_panel_update(state, sockfd, fp_ram, p->ai_addr, p->ai_addrlen); wait_for_next_clock_cycle(state); uint8_t syllable = extract_syllable_from_word(iw, state->active_thread->sc); execute_syllable(state, syllable);