Initial commit of `nedfp` as a front panel for `nedsim`.
[ned1] / nedsim / nedsim.c
index b88328b..be63706 100644 (file)
 #include <time.h>
 #include <termios.h>
 #include <signal.h>
 #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>
 
 #include "../common/a.out.h"
 
 
 #include "../common/a.out.h"
 
-#define VERSION 4
+#define VERSION 5
 
 /* Bytes per word. */
 #define BPW 4
 
 /* Bytes per word. */
 #define BPW 4
@@ -94,12 +99,14 @@ void
 print_usage(char ** argv)
 {
     printf( "NED Simulator v%d (www.subgeniuskitty.com)\n"
 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"
             "  -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"
             "                          Allowable values are 1 <= clock <= 1,000,000,000.\n"
-            "  -t <file>               Saves a trace of JMP and BRZ syllables to file.\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]
     );
 }
             , VERSION, argv[0]
     );
 }
@@ -634,6 +641,53 @@ parse_aout_file(FILE * input, struct exec * aout_exec, uint8_t * text_segment,
 
 }
 
 
 }
 
+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
 main(int argc, char ** argv)
@@ -645,27 +699,38 @@ main(int argc, char ** argv)
     FILE * input = NULL;
     FILE * trace = NULL;
     uint32_t clock_period = 1;
     FILE * input = NULL;
     FILE * trace = NULL;
     uint32_t clock_period = 1;
-    while ((c = getopt(argc,argv,"i:p:t: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) {
         switch (c) {
-            case 't':
-                if ((trace = fopen(optarg, "wx")) == NULL) {
+            case 'f':
+                if ((input = fopen(optarg, "r")) == NULL) {
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
                     exit(EXIT_FAILURE);
                 }
                 break;
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
                     exit(EXIT_FAILURE);
                 }
                 break;
-            case 'i':
-                if ((input = fopen(optarg, "r")) == NULL) {
+            case 't':
+                if ((trace = fopen(optarg, "wx")) == NULL) {
                     fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
                     exit(EXIT_FAILURE);
                 }
                 break;
                     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':
             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 {
                     } else {
-                        fprintf(stderr, "WARN: Clock period out of range.\n");
+                        fprintf(stderr, "WARNING: Clock period out of range.\n");
                     }
                     break;
                 }
                     }
                     break;
                 }
@@ -682,6 +747,7 @@ main(int argc, char ** argv)
         print_usage(argv);
         exit(EXIT_FAILURE);
     }
         print_usage(argv);
         exit(EXIT_FAILURE);
     }
+    if (fp_ip != NULL && fp_port == NULL) asprintf(&fp_port, "4999");
 
     /*
      * Initialization
 
     /*
      * Initialization
@@ -712,6 +778,37 @@ main(int argc, char ** argv)
     parse_aout_file(input, &aout_exec, &(state->ram[address]), &symbol_table, &symbol_count);
     fclose(input);
 
     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
      */
     /*
      * Main Loop
      */
@@ -761,6 +858,7 @@ main(int argc, char ** argv)
 
         /* Decode instruction word format and execute. */
         if (iw & (0b1 << 31)) {                /* Instruction word is type A. */
 
         /* 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;
             wait_for_next_clock_cycle(state);
             stack_push(state->active_thread, (iw << 1));
             state->active_thread->debug->cycle_count += 1;
@@ -769,6 +867,7 @@ main(int argc, char ** argv)
                 state->active_thread->sc < SPW;
                 state->active_thread->sc++
             ) {
                 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);
                 wait_for_next_clock_cycle(state);
                 uint8_t syllable = extract_syllable_from_word(iw, state->active_thread->sc);
                 execute_syllable(state, syllable);