Skip to content

Commit fb08e74

Browse files
committed
newemu: fd polling mechanism
1 parent bf1502e commit fb08e74

File tree

8 files changed

+201
-37
lines changed

8 files changed

+201
-37
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# PDP-6 Emulator
22

3-
This project aims to revive the PDP-6 (and later PDP-10)
4-
computers by DEC.
3+
This project aims to revive the PDP-6 computer by DEC.
54

65
I started by writing a very low level emulator in C based on
76
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
7271
tools/mkpty.c make a pty and connect to the controlling tty
7372
tools/mkpty33.c as above but try to pretend an ASR33
7473
tools/as6.c an assembler, roughly modeled on MACRO
75-
tools/ld6.c a loader or relocatable files
74+
tools/ld6.c a loader of relocatable files
7675
tools/pdp6bin.h
7776
tools/pdp6common.c useful functions for PDP-6 code
7877
tools/pdp6common.h

newemu/common.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,144 @@ split(char *line, int *pargc)
238238

239239
return argv;
240240
}
241+
242+
243+
#include <poll.h>
244+
245+
struct FDmsg
246+
{
247+
int msg;
248+
FD *fd;
249+
};
250+
251+
static FD *fds[100];
252+
static struct pollfd pfds[100];
253+
static int nfds;
254+
static int pollpipe[2] = { -1, -1 };
255+
256+
static void
257+
removeslot(int i)
258+
{
259+
pfds[i].revents = 0;
260+
pfds[i].events = 0;
261+
pfds[i].fd = -1;
262+
fds[i]->fd = -1;
263+
fds[i]->id = -1;
264+
fds[i]->ready = 0;
265+
fds[i] = nil;
266+
}
267+
268+
static void
269+
pollfds(void)
270+
{
271+
struct FDmsg msg;
272+
FD *fd;
273+
int i, n;
274+
275+
pipe(pollpipe);
276+
pfds[0].fd = pollpipe[0];
277+
pfds[0].events = POLLIN;
278+
nfds = 1;
279+
for(;;) {
280+
n = poll(pfds, nfds, -1);
281+
if(n < 0) {
282+
perror("error poll");
283+
return;
284+
}
285+
286+
/* someone wants us to watch their fd or has closed it */
287+
if(pfds[0].revents & POLLIN) {
288+
read(pfds[0].fd, &msg, sizeof(msg));
289+
fd = msg.fd;
290+
switch(msg.msg) {
291+
// wait
292+
case 1:
293+
if(fd->id >= 0) {
294+
/* already in list */
295+
assert(fds[fd->id] == fd);
296+
//printf("polling fd %d in slot %d\n", fd->fd, fd->id);
297+
} else {
298+
/* add to list */
299+
for(i = 1; i < nfds; i++)
300+
if(fds[i] == nil)
301+
break;
302+
assert(i < nelem(pfds));
303+
if(i == nfds) nfds++;
304+
fd->id = i;
305+
fds[fd->id] = fd;
306+
//printf("adding fd %d in slot %d\n", fd->fd, fd->id);
307+
}
308+
pfds[fd->id].fd = fd->fd;
309+
pfds[fd->id].events = POLLIN;
310+
pfds[fd->id].revents = 0;
311+
fd->ready = 0;
312+
break;
313+
314+
// close
315+
case 2:
316+
/* fd was closed */
317+
//printf("received close for fd %d slot %d\n", pfds[fd->id].fd, fd->id);
318+
assert(fd->id >= 0);
319+
close(pfds[fd->id].fd);
320+
removeslot(fd->id);
321+
break;
322+
}
323+
}
324+
325+
for(i = 1; i < nfds; i++) {
326+
/* fd was closed on other side */
327+
if(pfds[i].revents & POLLHUP) {
328+
//printf("fd %d hung up\n", pfds[i].fd);
329+
close(fds[i]->fd);
330+
removeslot(i);
331+
}
332+
if(pfds[i].revents & POLLIN) {
333+
//printf("fd %d became ready\n", pfds[i].fd);
334+
/* ignore this fd for now */
335+
pfds[i].fd = -1;
336+
pfds[i].events = 0;
337+
pfds[i].revents = 0;
338+
fds[i]->ready = 1;
339+
}
340+
if(pfds[i].revents)
341+
printf("more events on fd %d: %d\n", pfds[i].fd, pfds[i].revents);
342+
}
343+
}
344+
}
345+
346+
static void *pollthread(void *arg) { pollfds(); return nil; }
347+
348+
void
349+
startpolling(void)
350+
{
351+
pthread_t th;
352+
pthread_create(&th, nil, pollthread, nil);
353+
354+
// wait for thread to start so waitfd can do its thing
355+
while(((volatile int*)pollpipe)[0] < 0) usleep(1000);
356+
}
357+
358+
void
359+
waitfd(FD *fd)
360+
{
361+
struct FDmsg msg;
362+
if(fd->fd < 0)
363+
return;
364+
fd->ready = 0;
365+
msg.msg = 1;
366+
msg.fd = fd;
367+
write(pollpipe[1], &msg, sizeof(msg));
368+
}
369+
370+
void
371+
closefd(FD *fd)
372+
{
373+
struct FDmsg msg;
374+
printf("closing fd %d\n", fd->fd);
375+
int i = fd->id;
376+
msg.msg = 2;
377+
msg.fd = fd;
378+
write(pollpipe[1], &msg, sizeof(msg));
379+
// wait for thread to notice
380+
while(((volatile FD**)fds)[i] != nil) usleep(1);
381+
}

newemu/common.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,15 @@ void nsleep(u64 ns);
3232
#define NEVER (~0)
3333

3434
char **split(char *line, int *pargc);
35+
36+
37+
typedef struct FD FD;
38+
struct FD
39+
{
40+
int fd;
41+
int ready;
42+
int id;
43+
};
44+
void startpolling(void);
45+
void waitfd(FD *fd);
46+
void closefd(FD *fd);

newemu/dis340.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ enum Modes
1717

1818
struct Dis340
1919
{
20-
int fd;
20+
FD fd;
2121

2222
/* 344 interface for PDP-6.
2323
* no schematics unfortunately */
@@ -75,16 +75,16 @@ addcmd(Dis340 *dis, u32 cmd)
7575
{
7676
dis->cmdbuf[dis->ncmds++] = cmd;
7777
if(dis->ncmds == nelem(dis->cmdbuf)) {
78-
if(write(dis->fd, dis->cmdbuf, sizeof(dis->cmdbuf)) < sizeof(dis->cmdbuf))
79-
dis->fd = -1;
78+
if(write(dis->fd.fd, dis->cmdbuf, sizeof(dis->cmdbuf)) < sizeof(dis->cmdbuf))
79+
dis->fd.fd = -1;
8080
dis->ncmds = 0;
8181
}
8282
}
8383

8484
static void
8585
agedisplay(Dis340 *dis)
8686
{
87-
if(dis->fd < 0)
87+
if(dis->fd.fd < 0)
8888
return;
8989
u32 cmd = 511<<23;
9090
assert(dis->lasttime <= dis->simtime);
@@ -105,7 +105,7 @@ intensify(Dis340 *dis)
105105
if(dx*dx + dy*dy <= 4)
106106
dis->lp_find = 1;
107107
}
108-
if(dis->fd >= 0){
108+
if(dis->fd.fd >= 0){
109109
agedisplay(dis);
110110
u32 cmd;
111111
cmd = dis->x;
@@ -278,18 +278,21 @@ cycle_dis(PDP6 *pdp, IOdev *dev, int pwr)
278278
}
279279

280280
agedisplay(dis);
281-
if(dis->inputtimer < simtime) {
281+
if(dis->fd.fd >= 0 && dis->inputtimer < simtime) {
282282
dis->inputtimer = simtime + 30000000;
283-
if(hasinput(dis->fd)) {
283+
if(dis->fd.ready) {
284284
u32 cmds[512];
285-
int n = read(dis->fd, cmds, sizeof(cmds));
285+
int n = read(dis->fd.fd, cmds, sizeof(cmds));
286+
if(n <= 0)
287+
return;
286288
n /= 4;
287289
for(int i = 0; i < n; i++) {
288290
u32 cmd = cmds[i];
289291
dis->peny = cmd & 01777;
290292
dis->penx = (cmd>>10) & 01777;
291293
dis->pen = (cmd>>20) & 1;
292294
}
295+
waitfd(&dis->fd);
293296
}
294297
}
295298

@@ -615,7 +618,9 @@ static IOdev joy_dev = { 0, 0420, nil, handle_joy, nil };
615618
Dis340*
616619
attach_dis(PDP6 *pdp)
617620
{
618-
dis.fd = -1;
621+
dis.fd.fd = -1;
622+
dis.fd.id = -1;
623+
619624
installdev(pdp, &dis_dev);
620625

621626
installdev(pdp, &joy_dev);
@@ -626,7 +631,8 @@ attach_dis(PDP6 *pdp)
626631
void
627632
dis_connect(Dis340 *dis, int fd)
628633
{
629-
if(dis->fd >= 0)
630-
close(dis->fd);
631-
dis->fd = fd;
634+
if(dis->fd.fd >= 0)
635+
closefd(&dis->fd);
636+
dis->fd.fd = fd;
637+
waitfd(&dis->fd);
632638
}

newemu/main.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include <fcntl.h>
66
#include <unistd.h>
7-
#include <pthread.h>
7+
#include <time.h>
88

99
#include <signal.h>
1010

@@ -272,21 +272,25 @@ main(int argc, char *argv[])
272272
initemu(pdp);
273273
configmachine(pdp);
274274

275+
startpolling();
276+
275277
int dis_fd = dial(host, port);
276278
if(dis_fd < 0)
277279
printf("can't open display\n");
278280
nodelay(dis_fd);
279281
dis_connect(dis, dis_fd);
280282

281-
// const char *tape = "t/hello.rim";
283+
const char *tape = "t/hello.rim";
282284
// const char *tape = "t/ptp_test.rim";
283-
const char *tape = "t/bla.txt";
284-
pdp->ptr_fd = open(tape, O_RDONLY);
285+
// const char *tape = "t/bla.txt";
286+
pdp->ptr_fd.fd = open(tape, O_RDONLY);
287+
waitfd(&pdp->ptr_fd);
285288
pdp->ptp_fd = open("out.ptp", O_CREAT|O_WRONLY|O_TRUNC, 0644);
286289

287-
pdp->tty_fd = open("/tmp/tty", O_RDWR);
288-
if(pdp->tty_fd < 0)
290+
pdp->tty_fd.fd = open("/tmp/tty", O_RDWR);
291+
if(pdp->tty_fd.fd < 0)
289292
printf("can't open /tmp/tty\n");
293+
waitfd(&pdp->tty_fd);
290294

291295
emu(pdp, panel);
292296
return 0; // can't happen

newemu/pdp6.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ struct PDP6
209209
bool ptr_flag;
210210
bool ptr_b;
211211
int ptr_pia;
212-
int ptr_fd;
212+
FD ptr_fd;
213213
u64 ptr_timer;
214214

215215

@@ -224,7 +224,7 @@ struct PDP6
224224
u8 tti;
225225
//
226226
int tty_baud, tty_dly;
227-
int tty_fd;
227+
FD tty_fd;
228228
int tti_state;
229229
u64 tti_timer;
230230
u64 tto_timer;

newemu/pt.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,17 +217,15 @@ cycle_ptr(PDP6 *pdp, IOdev *dev, int pwr)
217217
pdp->ptr_timer = simtime + PTR_DLY;
218218
}
219219
pdp->ptr_clutch = clutch;
220-
if(!pdp->ptr_clutch || pdp->ptr_timer >= simtime)
220+
if(!pdp->ptr_clutch || pdp->ptr_fd.fd < 0 || pdp->ptr_timer >= simtime)
221221
return;
222222
pdp->ptr_timer = simtime + PTR_DLY;
223223

224-
if(!hasinput(pdp->ptr_fd))
224+
if(!pdp->ptr_fd.ready)
225225
return;
226-
if(read(pdp->ptr_fd, &c, 1) <= 0) {
227-
close(pdp->ptr_fd);
228-
pdp->ptr_fd = -1;
226+
if(read(pdp->ptr_fd.fd, &c, 1) <= 0)
229227
return;
230-
}
228+
waitfd(&pdp->ptr_fd);
231229
if(pdp->ptr_busy && (c & 0200 || !pdp->ptr_b)) {
232230
// PTR STROBE
233231
// actually 400μs after feed hole edge
@@ -262,5 +260,8 @@ calc_ptr_req(PDP6 *pdp)
262260
void
263261
attach_ptr(PDP6 *pdp)
264262
{
263+
pdp->ptr_fd.fd = -1;
264+
pdp->ptr_fd.id = -1;
265+
265266
installdev(pdp, &ptr_dev);
266267
}

newemu/tty.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ cycle_tty(PDP6 *pdp, IOdev *dev, int pwr)
6868

6969
if(pdp->tto_active && pdp->tto_timer < simtime) {
7070
pdp->tto_active = 0;
71-
if(pdp->tty_fd >= 0) {
71+
if(pdp->tty_fd.fd >= 0) {
7272
char c = pdp->tto & 0177;
73-
write(pdp->tty_fd, &c, 1);
73+
write(pdp->tty_fd.fd, &c, 1);
7474
}
7575
pdp->tto = 0;
7676
pdp->tto_busy = 0;
@@ -83,16 +83,14 @@ cycle_tty(PDP6 *pdp, IOdev *dev, int pwr)
8383
// t=0 read char
8484
// t=9 set flag (simulate reading done)
8585
// t=11 ready to accept next char
86-
if(pdp->tti_timer < simtime) {
86+
if(pdp->tty_fd.fd >= 0 && pdp->tti_timer < simtime) {
8787
pdp->tti_timer = simtime + pdp->tty_dly;
8888
if(pdp->tti_state == 0) {
89-
if(hasinput(pdp->tty_fd)) {
89+
if(pdp->tty_fd.ready) {
9090
char c;
91-
if(read(pdp->tty_fd, &c, 1) <= 0) {
92-
close(pdp->tty_fd);
93-
pdp->tty_fd = -1;
91+
if(read(pdp->tty_fd.fd, &c, 1) <= 0)
9492
return;
95-
}
93+
waitfd(&pdp->tty_fd);
9694
pdp->tti = c;
9795
pdp->tti_busy = 1;
9896
pdp->tti_flag = 0;
@@ -128,6 +126,9 @@ calc_tty_req(PDP6 *pdp)
128126
void
129127
attach_tty(PDP6 *pdp)
130128
{
129+
pdp->tty_fd.fd = -1;
130+
pdp->tty_fd.id = -1;
131+
131132
pdp->tty_baud = 110;
132133
pdp->tty_dly = 1000000000 / pdp->tty_baud;
133134
installdev(pdp, &tty_dev);

0 commit comments

Comments
 (0)