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:
@@ -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
|
||||
|
||||
141
newemu/common.c
141
newemu/common.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
13
newemu/pt.c
13
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);
|
||||
}
|
||||
|
||||
17
newemu/tty.c
17
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);
|
||||
|
||||
Reference in New Issue
Block a user