#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>
-#define VERSION 1
+#include "../common/a.out.h"
+
+#define VERSION 5
/* Bytes per word. */
#define BPW 4
print_usage(char ** argv)
{
printf( "NED Simulator v%d (www.subgeniuskitty.com)\n"
- "Usage: %s -i <file>\n"
+ "Usage: %s -f <file>\n"
" -h Help (prints this message)\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"
+ " -f <file> Specify a binary image file to load in RAM.\n"
+ " -s <int hz, optional> Frequency of simulated system clock.\n"
" Allowable values are 1 <= clock <= 1,000,000,000.\n"
+ " -t <file, optional> Saves a trace of JMP and BRZ syllables to file.\n"
+ " -i <ip-addr, optional> IP address of nedfp instance. Enables front panel output.\n"
+ " -p <port, optional> Port of nedfp instance. Required when '-i' specified.\n"
, VERSION, argv[0]
);
}
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;
}
}
+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)
{
*/
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:f:")) != -1) {
switch (c) {
- case 'i':
+ case 'f':
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 'i':
+ // 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;
}
print_usage(argv);
exit(EXIT_FAILURE);
}
+ if (fp_ip != NULL && fp_port == NULL) asprintf(&fp_port, "4999");
/*
* Initialization
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 */
/* 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;
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);