1
0
mirror of https://github.com/aap/pdp6.git synced 2026-02-27 01:10:14 +00:00

newemu: fd polling mechanism

This commit is contained in:
aap
2024-04-19 11:06:17 +02:00
parent bf1502e9ee
commit fb08e742b0
8 changed files with 201 additions and 37 deletions

View File

@@ -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

View File

@@ -238,3 +238,144 @@ split(char *line, int *pargc)
return argv;
}
#include <poll.h>
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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -4,7 +4,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <signal.h>
@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);