From fb08e742b0144aee40f55103f1eb7cd5da2c5754 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 19 Apr 2024 11:06:17 +0200 Subject: [PATCH] newemu: fd polling mechanism --- README.md | 5 +- newemu/common.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ newemu/common.h | 12 +++++ newemu/dis340.c | 30 ++++++----- newemu/main.c | 16 +++--- newemu/pdp6.h | 4 +- newemu/pt.c | 13 ++--- newemu/tty.c | 17 +++--- 8 files changed, 201 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 61b4487..f527f35 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # PDP-6 Emulator -This project aims to revive the PDP-6 (and later PDP-10) -computers by DEC. +This project aims to revive the PDP-6 computer by DEC. I started by writing a very low level emulator in C based on the schematics. Later I also wrote an accurate verilog simulation @@ -72,7 +71,7 @@ tools/dtr2dta.c convert between raw (dtr) and simh (dta) DECtape format tools/mkpty.c make a pty and connect to the controlling tty tools/mkpty33.c as above but try to pretend an ASR33 tools/as6.c an assembler, roughly modeled on MACRO -tools/ld6.c a loader or relocatable files +tools/ld6.c a loader of relocatable files tools/pdp6bin.h tools/pdp6common.c useful functions for PDP-6 code tools/pdp6common.h diff --git a/newemu/common.c b/newemu/common.c index 54f2bdf..e7f6379 100644 --- a/newemu/common.c +++ b/newemu/common.c @@ -238,3 +238,144 @@ split(char *line, int *pargc) return argv; } + + +#include + +struct FDmsg +{ + int msg; + FD *fd; +}; + +static FD *fds[100]; +static struct pollfd pfds[100]; +static int nfds; +static int pollpipe[2] = { -1, -1 }; + +static void +removeslot(int i) +{ + pfds[i].revents = 0; + pfds[i].events = 0; + pfds[i].fd = -1; + fds[i]->fd = -1; + fds[i]->id = -1; + fds[i]->ready = 0; + fds[i] = nil; +} + +static void +pollfds(void) +{ + struct FDmsg msg; + FD *fd; + int i, n; + + pipe(pollpipe); + pfds[0].fd = pollpipe[0]; + pfds[0].events = POLLIN; + nfds = 1; + for(;;) { + n = poll(pfds, nfds, -1); + if(n < 0) { + perror("error poll"); + return; + } + + /* someone wants us to watch their fd or has closed it */ + if(pfds[0].revents & POLLIN) { + read(pfds[0].fd, &msg, sizeof(msg)); + fd = msg.fd; + switch(msg.msg) { + // wait + case 1: + if(fd->id >= 0) { + /* already in list */ + assert(fds[fd->id] == fd); +//printf("polling fd %d in slot %d\n", fd->fd, fd->id); + } else { + /* add to list */ + for(i = 1; i < nfds; i++) + if(fds[i] == nil) + break; + assert(i < nelem(pfds)); + if(i == nfds) nfds++; + fd->id = i; + fds[fd->id] = fd; +//printf("adding fd %d in slot %d\n", fd->fd, fd->id); + } + pfds[fd->id].fd = fd->fd; + pfds[fd->id].events = POLLIN; + pfds[fd->id].revents = 0; + fd->ready = 0; + break; + + // close + case 2: + /* fd was closed */ +//printf("received close for fd %d slot %d\n", pfds[fd->id].fd, fd->id); + assert(fd->id >= 0); + close(pfds[fd->id].fd); + removeslot(fd->id); + break; + } + } + + for(i = 1; i < nfds; i++) { + /* fd was closed on other side */ + if(pfds[i].revents & POLLHUP) { +//printf("fd %d hung up\n", pfds[i].fd); + close(fds[i]->fd); + removeslot(i); + } + if(pfds[i].revents & POLLIN) { +//printf("fd %d became ready\n", pfds[i].fd); + /* ignore this fd for now */ + pfds[i].fd = -1; + pfds[i].events = 0; + pfds[i].revents = 0; + fds[i]->ready = 1; + } + if(pfds[i].revents) + printf("more events on fd %d: %d\n", pfds[i].fd, pfds[i].revents); + } + } +} + +static void *pollthread(void *arg) { pollfds(); return nil; } + +void +startpolling(void) +{ + pthread_t th; + pthread_create(&th, nil, pollthread, nil); + + // wait for thread to start so waitfd can do its thing + while(((volatile int*)pollpipe)[0] < 0) usleep(1000); +} + +void +waitfd(FD *fd) +{ + struct FDmsg msg; + if(fd->fd < 0) + return; + fd->ready = 0; + msg.msg = 1; + msg.fd = fd; + write(pollpipe[1], &msg, sizeof(msg)); +} + +void +closefd(FD *fd) +{ + struct FDmsg msg; + printf("closing fd %d\n", fd->fd); + int i = fd->id; + msg.msg = 2; + msg.fd = fd; + write(pollpipe[1], &msg, sizeof(msg)); + // wait for thread to notice + while(((volatile FD**)fds)[i] != nil) usleep(1); +} diff --git a/newemu/common.h b/newemu/common.h index dde462f..dd88b0f 100644 --- a/newemu/common.h +++ b/newemu/common.h @@ -32,3 +32,15 @@ void nsleep(u64 ns); #define NEVER (~0) char **split(char *line, int *pargc); + + +typedef struct FD FD; +struct FD +{ + int fd; + int ready; + int id; +}; +void startpolling(void); +void waitfd(FD *fd); +void closefd(FD *fd); diff --git a/newemu/dis340.c b/newemu/dis340.c index 3cb9c4e..d8a7419 100644 --- a/newemu/dis340.c +++ b/newemu/dis340.c @@ -17,7 +17,7 @@ enum Modes struct Dis340 { - int fd; + FD fd; /* 344 interface for PDP-6. * no schematics unfortunately */ @@ -75,8 +75,8 @@ addcmd(Dis340 *dis, u32 cmd) { dis->cmdbuf[dis->ncmds++] = cmd; if(dis->ncmds == nelem(dis->cmdbuf)) { - if(write(dis->fd, dis->cmdbuf, sizeof(dis->cmdbuf)) < sizeof(dis->cmdbuf)) - dis->fd = -1; + if(write(dis->fd.fd, dis->cmdbuf, sizeof(dis->cmdbuf)) < sizeof(dis->cmdbuf)) + dis->fd.fd = -1; dis->ncmds = 0; } } @@ -84,7 +84,7 @@ addcmd(Dis340 *dis, u32 cmd) static void agedisplay(Dis340 *dis) { - if(dis->fd < 0) + if(dis->fd.fd < 0) return; u32 cmd = 511<<23; assert(dis->lasttime <= dis->simtime); @@ -105,7 +105,7 @@ intensify(Dis340 *dis) if(dx*dx + dy*dy <= 4) dis->lp_find = 1; } - if(dis->fd >= 0){ + if(dis->fd.fd >= 0){ agedisplay(dis); u32 cmd; cmd = dis->x; @@ -278,11 +278,13 @@ cycle_dis(PDP6 *pdp, IOdev *dev, int pwr) } agedisplay(dis); - if(dis->inputtimer < simtime) { + if(dis->fd.fd >= 0 && dis->inputtimer < simtime) { dis->inputtimer = simtime + 30000000; - if(hasinput(dis->fd)) { + if(dis->fd.ready) { u32 cmds[512]; - int n = read(dis->fd, cmds, sizeof(cmds)); + int n = read(dis->fd.fd, cmds, sizeof(cmds)); + if(n <= 0) + return; n /= 4; for(int i = 0; i < n; i++) { u32 cmd = cmds[i]; @@ -290,6 +292,7 @@ cycle_dis(PDP6 *pdp, IOdev *dev, int pwr) dis->penx = (cmd>>10) & 01777; dis->pen = (cmd>>20) & 1; } + waitfd(&dis->fd); } } @@ -615,7 +618,9 @@ static IOdev joy_dev = { 0, 0420, nil, handle_joy, nil }; Dis340* attach_dis(PDP6 *pdp) { - dis.fd = -1; + dis.fd.fd = -1; + dis.fd.id = -1; + installdev(pdp, &dis_dev); installdev(pdp, &joy_dev); @@ -626,7 +631,8 @@ attach_dis(PDP6 *pdp) void dis_connect(Dis340 *dis, int fd) { - if(dis->fd >= 0) - close(dis->fd); - dis->fd = fd; + if(dis->fd.fd >= 0) + closefd(&dis->fd); + dis->fd.fd = fd; + waitfd(&dis->fd); } diff --git a/newemu/main.c b/newemu/main.c index 200dbf0..0d8d703 100644 --- a/newemu/main.c +++ b/newemu/main.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include @@ -272,21 +272,25 @@ main(int argc, char *argv[]) initemu(pdp); configmachine(pdp); + startpolling(); + int dis_fd = dial(host, port); if(dis_fd < 0) printf("can't open display\n"); nodelay(dis_fd); dis_connect(dis, dis_fd); -// const char *tape = "t/hello.rim"; + const char *tape = "t/hello.rim"; // const char *tape = "t/ptp_test.rim"; - const char *tape = "t/bla.txt"; - pdp->ptr_fd = open(tape, O_RDONLY); +// const char *tape = "t/bla.txt"; + pdp->ptr_fd.fd = open(tape, O_RDONLY); + waitfd(&pdp->ptr_fd); pdp->ptp_fd = open("out.ptp", O_CREAT|O_WRONLY|O_TRUNC, 0644); - pdp->tty_fd = open("/tmp/tty", O_RDWR); - if(pdp->tty_fd < 0) + pdp->tty_fd.fd = open("/tmp/tty", O_RDWR); + if(pdp->tty_fd.fd < 0) printf("can't open /tmp/tty\n"); + waitfd(&pdp->tty_fd); emu(pdp, panel); return 0; // can't happen diff --git a/newemu/pdp6.h b/newemu/pdp6.h index eb72e94..0e4623a 100644 --- a/newemu/pdp6.h +++ b/newemu/pdp6.h @@ -209,7 +209,7 @@ struct PDP6 bool ptr_flag; bool ptr_b; int ptr_pia; - int ptr_fd; + FD ptr_fd; u64 ptr_timer; @@ -224,7 +224,7 @@ struct PDP6 u8 tti; // int tty_baud, tty_dly; - int tty_fd; + FD tty_fd; int tti_state; u64 tti_timer; u64 tto_timer; diff --git a/newemu/pt.c b/newemu/pt.c index a54f471..c306521 100644 --- a/newemu/pt.c +++ b/newemu/pt.c @@ -217,17 +217,15 @@ cycle_ptr(PDP6 *pdp, IOdev *dev, int pwr) pdp->ptr_timer = simtime + PTR_DLY; } pdp->ptr_clutch = clutch; - if(!pdp->ptr_clutch || pdp->ptr_timer >= simtime) + if(!pdp->ptr_clutch || pdp->ptr_fd.fd < 0 || pdp->ptr_timer >= simtime) return; pdp->ptr_timer = simtime + PTR_DLY; - if(!hasinput(pdp->ptr_fd)) + if(!pdp->ptr_fd.ready) return; - if(read(pdp->ptr_fd, &c, 1) <= 0) { - close(pdp->ptr_fd); - pdp->ptr_fd = -1; + if(read(pdp->ptr_fd.fd, &c, 1) <= 0) return; - } + waitfd(&pdp->ptr_fd); if(pdp->ptr_busy && (c & 0200 || !pdp->ptr_b)) { // PTR STROBE // actually 400μs after feed hole edge @@ -262,5 +260,8 @@ calc_ptr_req(PDP6 *pdp) void attach_ptr(PDP6 *pdp) { + pdp->ptr_fd.fd = -1; + pdp->ptr_fd.id = -1; + installdev(pdp, &ptr_dev); } diff --git a/newemu/tty.c b/newemu/tty.c index af6116d..82499b5 100644 --- a/newemu/tty.c +++ b/newemu/tty.c @@ -68,9 +68,9 @@ cycle_tty(PDP6 *pdp, IOdev *dev, int pwr) if(pdp->tto_active && pdp->tto_timer < simtime) { pdp->tto_active = 0; - if(pdp->tty_fd >= 0) { + if(pdp->tty_fd.fd >= 0) { char c = pdp->tto & 0177; - write(pdp->tty_fd, &c, 1); + write(pdp->tty_fd.fd, &c, 1); } pdp->tto = 0; pdp->tto_busy = 0; @@ -83,16 +83,14 @@ cycle_tty(PDP6 *pdp, IOdev *dev, int pwr) // t=0 read char // t=9 set flag (simulate reading done) // t=11 ready to accept next char - if(pdp->tti_timer < simtime) { + if(pdp->tty_fd.fd >= 0 && pdp->tti_timer < simtime) { pdp->tti_timer = simtime + pdp->tty_dly; if(pdp->tti_state == 0) { - if(hasinput(pdp->tty_fd)) { + if(pdp->tty_fd.ready) { char c; - if(read(pdp->tty_fd, &c, 1) <= 0) { - close(pdp->tty_fd); - pdp->tty_fd = -1; + if(read(pdp->tty_fd.fd, &c, 1) <= 0) return; - } + waitfd(&pdp->tty_fd); pdp->tti = c; pdp->tti_busy = 1; pdp->tti_flag = 0; @@ -128,6 +126,9 @@ calc_tty_req(PDP6 *pdp) void attach_tty(PDP6 *pdp) { + pdp->tty_fd.fd = -1; + pdp->tty_fd.id = -1; + pdp->tty_baud = 110; pdp->tty_dly = 1000000000 / pdp->tty_baud; installdev(pdp, &tty_dev);