Let HRCG terminal run a child process, with pty for bidirectional communication
authorNick Downing <nick@ndcode.org>
Wed, 25 May 2022 16:18:55 +0000 (02:18 +1000)
committerNick Downing <nick@ndcode.org>
Wed, 25 May 2022 16:18:55 +0000 (02:18 +1000)
hrcg/emu_65c02.c
hrcg/ribbit.sh

index b20e2ca..742ef38 100644 (file)
@@ -1,9 +1,12 @@
+#define _XOPEN_SOURCE 600
 #include <fcntl.h>
 #include <poll.h>
+#include <signal.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/wait.h>
 #include <termios.h>
 #include <unistd.h>
 #include <SDL2/SDL.h>
@@ -24,7 +27,7 @@
 #define WINDOW_WIDTH (PADDED_WIDTH * WINDOW_X_SCALE)
 #define WINDOW_HEIGHT (PADDED_HEIGHT * WINDOW_Y_SCALE)
 
-#define INSTRS_PER_UPDATE 1500
+#define INSTRS_PER_UPDATE 15000
 
 #define IO_PAGE 0xc000
 #define IO_KBD 0xc000
 
 #define TRACE 0
 
+extern char **environ;
+
+int fd_in = STDIN_FILENO;
+int fd_out = STDOUT_FILENO;
+int child_pid;
 struct termios termios_attr;
 
 SDL_Window *window;
@@ -223,7 +231,7 @@ uint8_t mem_read(uint16_t addr, bool isDbg) {
   case STDIN_DATA:
     {
       uint8_t data = 'X' - 0x40;
-      ssize_t count = read(STDIN_FILENO, &data, 1);
+      ssize_t count = read(fd_in, &data, 1);
       if (count == -1) {
         perror("read()");
         exit(EXIT_FAILURE);
@@ -236,7 +244,7 @@ uint8_t mem_read(uint16_t addr, bool isDbg) {
     }
   case STDIN_STATUS:
     {
-      struct pollfd fd = {STDIN_FILENO, POLLIN | POLLPRI, 0};
+      struct pollfd fd = {fd_in, POLLIN | POLLPRI, 0};
       if (poll(&fd, 1, 0) == -1) {
         perror("poll()");
         exit(EXIT_FAILURE);
@@ -245,7 +253,7 @@ uint8_t mem_read(uint16_t addr, bool isDbg) {
     }
   case STDOUT_STATUS:
     {
-      struct pollfd fd = {STDOUT_FILENO, POLLOUT, 0};
+      struct pollfd fd = {fd_out, POLLOUT, 0};
       if (poll(&fd, 1, 0) == -1) {
         perror("poll()");
         exit(EXIT_FAILURE);
@@ -286,7 +294,7 @@ void mem_write(uint16_t addr, uint8_t val) {
     hires = APPLE_HIRES1;
     break;
   case STDOUT_DATA:
-    if (write(STDOUT_FILENO, &val, 1) == -1) {
+    if (write(fd_out, &val, 1) == -1) {
       perror("write()");
       exit(EXIT_FAILURE);
     }
@@ -317,8 +325,30 @@ void mem_write(uint16_t addr, uint8_t val) {
   }
 }
 
+void sigchld_handler(int signum) {
+  if (child_pid == 0) {
+    fprintf(stderr, "SIGCHLD: no child process yet\n");
+    exit(EXIT_FAILURE);
+  }
+
+  int wstatus;
+  if (waitpid(child_pid, &wstatus, WNOHANG) == -1) {
+    perror("waitpid()");
+    exit(EXIT_FAILURE);
+  }
+
+  if (!WIFEXITED(wstatus)) {
+    fprintf(stderr, "SIGCHLD: child process was killed\n");
+    exit(EXIT_FAILURE);
+  }
+
+  // reflect child's exit status to parent
+  //fprintf(stderr, "SIGCHLD: child exit status %d\n", WEXITSTATUS(wstatus));
+  exit(WEXITSTATUS(wstatus));
+}
+
 void termios_atexit(void) {
-  if (tcsetattr(STDIN_FILENO, TCSADRAIN, &termios_attr) == -1)
+  if (tcsetattr(fd_in, TCSADRAIN, &termios_attr) == -1)
     perror("tcsetattr()");
 }
 
@@ -331,20 +361,75 @@ int main(int argc, char **argv) {
   }
 
   if (argn >= argc) {
-    printf("usage: %s [-t] program.bin\n", argv[0]);
+    printf("usage: %s [-t] [utility.obj ...] program.obj [-- child_executable [child_argument ...]]\n", argv[0]);
     exit(EXIT_FAILURE);
   }
 
   int load_address = 0;
-  while (argn < argc)
-    load_address = bload(argv[argn++]);
+  while (argn < argc) {
+    char *p = argv[argn++];
+    if (strcmp(p, "--") == 0)
+      break;
+    load_address = bload(p);
+  }
+
+  // open pty and child process if requested
+  if (argn < argc) {
+    int fd_master = posix_openpt(O_RDWR);
+    if (fd_master == -1) {
+      perror("posix_openpt()");
+      exit(EXIT_FAILURE);
+    }
+
+    if (grantpt(fd_master) == -1) {
+      perror("grantpt()");
+      exit(EXIT_FAILURE);
+    }
+
+    if (unlockpt(fd_master) == -1) {
+      perror("unlockpt()");
+      exit(EXIT_FAILURE);
+    }
+
+    // Open the slave side ot the PTY
+    int fd_slave;
+    {
+      char *p = ptsname(fd_master);
+      fd_slave = open(p, O_RDWR);
+      if (fd_slave == -1) {
+        perror(p);
+        exit(EXIT_FAILURE);
+      }
+    }
+
+    signal(SIGCHLD, sigchld_handler);
+    child_pid = fork();
+    if (child_pid == 0) {
+      dup2(fd_slave, STDIN_FILENO);
+      dup2(fd_slave, STDOUT_FILENO);
+      dup2(fd_slave, STDERR_FILENO);
+
+      int n = argc - argn;
+      char **p = malloc((n + 1) * sizeof(char *));
+      memcpy(p, argv + argn, n * sizeof(char *));
+      p[n] = NULL;
+      execve(argv[argn], p, environ);
+
+      perror(argv[argn]);
+      exit(EXIT_FAILURE);
+    }
+
+    fd_in = fd_master;
+    fd_out = fd_master;
+    close(fd_slave);
+  }
 
   // do this before creating the CPU
   mem[RESET_VECTOR] = (uint8_t)(load_address & 0xff);
   mem[RESET_VECTOR + 1] = (uint8_t)(load_address >> 8);
 
-  if (isatty(STDIN_FILENO)) {
-    if (tcgetattr(STDIN_FILENO, &termios_attr) == -1) {
+  if (isatty(fd_in)) {
+    if (tcgetattr(fd_in, &termios_attr) == -1) {
       perror("tcgetattr()");
       exit(EXIT_FAILURE);
     }
@@ -359,7 +444,7 @@ int main(int argc, char **argv) {
     attr.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
     attr.c_cc[VMIN] = 1;
     attr.c_cc[VTIME] = 0;
-    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) == -1) {
+    if (tcsetattr(fd_in, TCSAFLUSH, &attr) == -1) {
       perror("tcsetattr()");
       exit(EXIT_FAILURE);
     }
@@ -506,7 +591,7 @@ int main(int argc, char **argv) {
 
     if (usleep_count) {
 #if 1 // hack to avoid lagginess in ribbit game
-      struct pollfd fd = {STDIN_FILENO, POLLIN | POLLPRI, 0};
+      struct pollfd fd = {fd_in, POLLIN | POLLPRI, 0};
       if (poll(&fd, 1, (usleep_count + 999) / 1000) == -1) {
         perror("poll()");
         exit(EXIT_FAILURE);
index f125f3e..16a723d 100755 (executable)
@@ -1,3 +1,2 @@
 #!/bin/sh
-../applesoft_basic.py --hrcg --joystick=/dev/input/by-id/usb-Madcatz_Mad_Catz_V.1_Stick-event-joystick,flip_y,swap_buttons ../ribbit/ribbit_patched.tok |\
-./emu_65c02 monitor_rom.obj hrcg.obj terminal.obj
+./emu_65c02 monitor_rom.obj hrcg.obj terminal.obj -- ../applesoft_basic.py --hrcg --joystick=/dev/input/by-id/usb-Madcatz_Mad_Catz_V.1_Stick-event-joystick,flip_y,swap_buttons ../ribbit/ribbit_patched.tok