mirror of
https://github.com/prirun/p50em.git
synced 2026-03-07 11:07:01 +00:00
Compare commits
6 Commits
rjemaster
...
spamxonkil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6d01cd05c | ||
|
|
ea2edd89de | ||
|
|
3d71fd85f0 | ||
|
|
5d119bb2c5 | ||
|
|
aa8095217f | ||
|
|
89043d09a4 |
@@ -22,6 +22,9 @@ the host processor having a large set of general-purpose registers.
|
|||||||
Coming soon, we swear! There is a unix man page included in this
|
Coming soon, we swear! There is a unix man page included in this
|
||||||
repository.
|
repository.
|
||||||
|
|
||||||
|
Github discussions are now enabled for this repository, and can be
|
||||||
|
used to ask for help.
|
||||||
|
|
||||||
## Public Systems
|
## Public Systems
|
||||||
|
|
||||||
There are a set of emulators available for public use. These may be
|
There are a set of emulators available for public use. These may be
|
||||||
|
|||||||
50
devamlc.h
50
devamlc.h
@@ -262,6 +262,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
unsigned short ctinterrupt; /* 1 bit per line */
|
unsigned short ctinterrupt; /* 1 bit per line */
|
||||||
unsigned short dss; /* 1 bit per line */
|
unsigned short dss; /* 1 bit per line */
|
||||||
unsigned short connected; /* 1 bit per line */
|
unsigned short connected; /* 1 bit per line */
|
||||||
|
unsigned short dolineclear; /* 1 bit per line */
|
||||||
unsigned short serial; /* true if any CT_SERIAL lines */
|
unsigned short serial; /* true if any CT_SERIAL lines */
|
||||||
unsigned short dsstime; /* countdown to dss poll */
|
unsigned short dsstime; /* countdown to dss poll */
|
||||||
short fd[16]; /* Unix fd, 1 per line */
|
short fd[16]; /* Unix fd, 1 per line */
|
||||||
@@ -329,6 +330,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
for (dx=0; dx<MAXBOARDS; dx++) {
|
for (dx=0; dx<MAXBOARDS; dx++) {
|
||||||
dc[dx].deviceid = 0;
|
dc[dx].deviceid = 0;
|
||||||
dc[dx].connected = 0;
|
dc[dx].connected = 0;
|
||||||
|
dc[dx].dolineclear = 0;
|
||||||
dc[dx].serial = 0;
|
dc[dx].serial = 0;
|
||||||
for (lx = 0; lx < 16; lx++) {
|
for (lx = 0; lx < 16; lx++) {
|
||||||
dc[dx].fd[lx] = -1;
|
dc[dx].fd[lx] = -1;
|
||||||
@@ -885,6 +887,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
close(dc[i].fd[lx]);
|
close(dc[i].fd[lx]);
|
||||||
dc[i].dss |= BITMASK16(lx+1);
|
dc[i].dss |= BITMASK16(lx+1);
|
||||||
dc[i].connected |= BITMASK16(lx+1);
|
dc[i].connected |= BITMASK16(lx+1);
|
||||||
|
dc[i].dolineclear |= BITMASK16(lx+1);
|
||||||
dc[i].fd[lx] = fd;
|
dc[i].fd[lx] = fd;
|
||||||
dc[i].tstate[lx] = TS_DATA;
|
dc[i].tstate[lx] = TS_DATA;
|
||||||
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
|
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
|
||||||
@@ -1140,6 +1143,53 @@ dorecv:
|
|||||||
if (dc[dx].deviceid == 0 || dc[dx].connected == 0 || dc[dx].eor)
|
if (dc[dx].deviceid == 0 || dc[dx].connected == 0 || dc[dx].eor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Inject xon / kill if dolineclear is true */
|
||||||
|
|
||||||
|
if (dolinecleararg)
|
||||||
|
for (lx = 0; lx < 16; lx++)
|
||||||
|
if (dc[dx].dolineclear & BITMASK16(lx+1))
|
||||||
|
{
|
||||||
|
unsigned char ch;
|
||||||
|
unsigned short utemp;
|
||||||
|
int dmcpair, lcount;
|
||||||
|
ea_t dmcea, dmcbufbegea, dmcbufendea;
|
||||||
|
unsigned short dmcnw;
|
||||||
|
|
||||||
|
if (dc[dx].bufnum)
|
||||||
|
dmcea = dc[dx].dmcchan + 2;
|
||||||
|
else
|
||||||
|
dmcea = dc[dx].dmcchan;
|
||||||
|
dmcpair = get32io(dmcea);
|
||||||
|
dmcbufbegea = dmcpair>>16;
|
||||||
|
dmcbufendea = dmcpair & 0xffff;
|
||||||
|
dmcnw = dmcbufendea - dmcbufbegea + 1;
|
||||||
|
|
||||||
|
if (dmcnw < 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
utemp = lx<<12 | 0x0200 | 0221; /* dc1/xon */
|
||||||
|
put16io(utemp, dmcbufbegea);
|
||||||
|
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||||
|
|
||||||
|
ch = (unsigned char)get16(MAKEVA(014, 0705));
|
||||||
|
utemp = lx<<12 | 0x0200 | ch; /* kill */
|
||||||
|
put16io(utemp, dmcbufbegea);
|
||||||
|
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||||
|
|
||||||
|
dc[dx].recvlx = lx;
|
||||||
|
if (dmcbufbegea-1 > dmcbufendea)
|
||||||
|
fatal("AMLC tumble table overflowed?");
|
||||||
|
put16io(dmcbufbegea, dmcea);
|
||||||
|
if (dmcbufbegea > dmcbufendea) { /* end of range has occurred */
|
||||||
|
dc[dx].bufnum = 1-dc[dx].bufnum;
|
||||||
|
dc[dx].eor = 1;
|
||||||
|
neweor = 1;
|
||||||
|
anyeor = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc[dx].dolineclear &= ~BITMASK16(lx+1);
|
||||||
|
}
|
||||||
|
|
||||||
/* select to see which lines have data to be read */
|
/* select to see which lines have data to be read */
|
||||||
|
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
|
|||||||
504
devsmlc.h
504
devsmlc.h
@@ -1,4 +1,3 @@
|
|||||||
#define DEBUG 0
|
|
||||||
/*
|
/*
|
||||||
Implements the SMLC subsystem for Primos.
|
Implements the SMLC subsystem for Primos.
|
||||||
|
|
||||||
@@ -48,8 +47,10 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#define SMLC_DEVICEID 0050 /* HSSMLC/MDLC is '50, SMLC is '56 */
|
#define SMLC_DEVICEID 0050 /* HSSMLC/MDLC is '50, SMLC is '56 */
|
||||||
|
|
||||||
@@ -111,12 +112,12 @@
|
|||||||
#define SMLC_ACK0_STATUS (007<<4) /* encoded ACK0 status */
|
#define SMLC_ACK0_STATUS (007<<4) /* encoded ACK0 status */
|
||||||
#define SMLC_NAK_STATUS (013<<4) /* encoded NAK status */
|
#define SMLC_NAK_STATUS (013<<4) /* encoded NAK status */
|
||||||
#define SMLC_ENQ_STATUS (014<<4) /* encoded soh-ENQ status */
|
#define SMLC_ENQ_STATUS (014<<4) /* encoded soh-ENQ status */
|
||||||
|
#define SMLC_MASK_STATUS (017<<4) /* encoded status mask */
|
||||||
|
|
||||||
/* seconds between attempts to make TCP connections */
|
/* seconds between attempts to make TCP connections */
|
||||||
|
|
||||||
#define SMLC_CONNECTINTERVAL 15
|
#define SMLC_CONNECTINTERVAL 15
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
#define HexColumn(x) (3 * (x) + 4)
|
#define HexColumn(x) (3 * (x) + 4)
|
||||||
#define AsciiColumn(x) (HexColumn(16) + 2 + (x))
|
#define AsciiColumn(x) (HexColumn(16) + 2 + (x))
|
||||||
#define LogLineLength (AsciiColumn(16))
|
#define LogLineLength (AsciiColumn(16))
|
||||||
@@ -124,11 +125,9 @@
|
|||||||
static void smlclogbytes(unsigned char *bytes, int len);
|
static void smlclogbytes(unsigned char *bytes, int len);
|
||||||
static void smlclogflush(void);
|
static void smlclogflush(void);
|
||||||
|
|
||||||
static FILE *smlclog = NULL;
|
|
||||||
static char smlclogbuf[LogLineLength + 1];
|
static char smlclogbuf[LogLineLength + 1];
|
||||||
static int smlclogbytescol = 0;
|
static int smlclogbytescol = 0;
|
||||||
static char smlctimestamp[20];
|
static char smlctimestamp[20];
|
||||||
#endif
|
|
||||||
|
|
||||||
/* connection states */
|
/* connection states */
|
||||||
|
|
||||||
@@ -144,7 +143,9 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
SMLC_STATERCVSYN = 0,
|
SMLC_STATERCVSYN = 0,
|
||||||
SMLC_STATERCVDLE,
|
SMLC_STATERCVDLE,
|
||||||
SMLC_STATERCVCHAR
|
SMLC_STATERCVCHAR,
|
||||||
|
SMLC_STATERCVSOH,
|
||||||
|
SMLC_STATERCVENQ
|
||||||
} SmlcReceiveState;
|
} SmlcReceiveState;
|
||||||
|
|
||||||
/* controller interrupt states */
|
/* controller interrupt states */
|
||||||
@@ -155,20 +156,18 @@ typedef enum {
|
|||||||
SMLC_INTERRUPTPENDING
|
SMLC_INTERRUPTPENDING
|
||||||
} SmlcInterruptState;
|
} SmlcInterruptState;
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
static char *intstates[] = {
|
static char *intstates[] = {
|
||||||
"not interrupting",
|
"not interrupting",
|
||||||
"interrupting",
|
"interrupting",
|
||||||
"interrupt pending"
|
"interrupt pending"
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
/* send/receive buffer */
|
/* send/receive buffer */
|
||||||
|
|
||||||
typedef struct smlcbuffer {
|
typedef struct smlcbuffer {
|
||||||
unsigned short in;
|
unsigned short in;
|
||||||
unsigned short out;
|
unsigned short out;
|
||||||
char data[SMLC_BUFSIZE];
|
unsigned char data[SMLC_BUFSIZE];
|
||||||
} SmlcBuffer;
|
} SmlcBuffer;
|
||||||
|
|
||||||
/* Simplex Line Control Block. */
|
/* Simplex Line Control Block. */
|
||||||
@@ -195,7 +194,7 @@ typedef struct plcb { /* physical line control block */
|
|||||||
SmlcReceiveState recvstate; /* receive state */
|
SmlcReceiveState recvstate; /* receive state */
|
||||||
bool starting; /* TRUE if waiting for response to SOH-ENQ */
|
bool starting; /* TRUE if waiting for response to SOH-ENQ */
|
||||||
bool naksent; /* TRUE if last frame sent was a NAK */
|
bool naksent; /* TRUE if last frame sent was a NAK */
|
||||||
int fd; /* Unix fd */
|
int fd; /* Unix file descriptor of socket */
|
||||||
char *remoteID; /* remote TCP endpoint identifier */
|
char *remoteID; /* remote TCP endpoint identifier */
|
||||||
uint32_t host; /* TCP host */
|
uint32_t host; /* TCP host */
|
||||||
unsigned short port; /* TCP port */
|
unsigned short port; /* TCP port */
|
||||||
@@ -225,19 +224,12 @@ static void smlcaddstatus(SmlcDCB *dcbp, int line, unsigned short status) {
|
|||||||
dmcbufbegea = dmcpair >> 16;
|
dmcbufbegea = dmcpair >> 16;
|
||||||
dmcbufendea = dmcpair & 0xffff;
|
dmcbufendea = dmcpair & 0xffff;
|
||||||
if (dmcbufendea >= dmcbufbegea) {
|
if (dmcbufendea >= dmcbufbegea) {
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Interrupt status '%06o added for line %d on device '%02o, next '%06o, last '%06o\n",
|
||||||
fprintf(smlclog, "%s Interrupt status '%06o added for line %d on device '%02o, next '%06o, last '%06o\n",
|
|
||||||
smlctimestamp, status, line, dcbp->deviceid, dmcbufbegea, dmcbufendea);
|
smlctimestamp, status, line, dcbp->deviceid, dmcbufbegea, dmcbufendea);
|
||||||
#endif
|
|
||||||
put16io(status + (line * 2), dmcbufbegea);
|
put16io(status + (line * 2), dmcbufbegea);
|
||||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||||
put16io(dmcbufbegea, dcbp->dmcstatus);
|
put16io(dmcbufbegea, dcbp->dmcstatus);
|
||||||
dcbp->intstate = SMLC_INTERRUPTPENDING;
|
dcbp->intstate = SMLC_INTERRUPTPENDING;
|
||||||
#if DEBUG
|
|
||||||
} else {
|
|
||||||
fprintf(smlclog, "%s Interrupt status '%06o -NOT- added for line %d on device '%02o, next '%06o, last '%06o\n",
|
|
||||||
smlctimestamp, status, line, dcbp->deviceid, dmcbufbegea, dmcbufendea);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +240,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
static int optenable = 1;
|
static int optenable = 1;
|
||||||
static struct timeval timeout = {0, 0};
|
static struct timeval timeout = {0, 0};
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addrlen;
|
||||||
char *bp;
|
char *bp;
|
||||||
char buf[SMLC_BUFSIZE];
|
char buf[SMLC_BUFSIZE];
|
||||||
int bufidx;
|
int bufidx;
|
||||||
@@ -259,11 +253,12 @@ int devsmlc (int class, int func, int device) {
|
|||||||
short dmcnw;
|
short dmcnw;
|
||||||
unsigned int dmcpair;
|
unsigned int dmcpair;
|
||||||
int dx;
|
int dx;
|
||||||
char *ep;
|
unsigned char *ep;
|
||||||
int fd;
|
int fd;
|
||||||
|
int flags;
|
||||||
uint32_t hostaddr;
|
uint32_t hostaddr;
|
||||||
int i;
|
int i;
|
||||||
char *ip;
|
unsigned char *ip;
|
||||||
PLCB *lp;
|
PLCB *lp;
|
||||||
bool isetb;
|
bool isetb;
|
||||||
int lx;
|
int lx;
|
||||||
@@ -271,11 +266,10 @@ int devsmlc (int class, int func, int device) {
|
|||||||
int maxfd;
|
int maxfd;
|
||||||
int n;
|
int n;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
char *np;
|
unsigned char *np;
|
||||||
char *op;
|
unsigned char *op;
|
||||||
socklen_t optlen;
|
socklen_t optlen;
|
||||||
int optval;
|
int optval;
|
||||||
struct sockaddr_in raddr;
|
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
int readycount;
|
int readycount;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -284,16 +278,14 @@ int devsmlc (int class, int func, int device) {
|
|||||||
int sx;
|
int sx;
|
||||||
unsigned short word;
|
unsigned short word;
|
||||||
fd_set writefds;
|
fd_set writefds;
|
||||||
#if DEBUG
|
|
||||||
struct tm *tp;
|
struct tm *tp;
|
||||||
struct timespec sts;
|
struct timespec sts;
|
||||||
#endif
|
|
||||||
|
|
||||||
currenttime = time(0);
|
currenttime = time(0);
|
||||||
#if DEBUG
|
#ifndef NOTRACE
|
||||||
tp = localtime(¤ttime);
|
tp = localtime(¤ttime);
|
||||||
clock_gettime(CLOCK_REALTIME, &sts);
|
clock_gettime(CLOCK_REALTIME, &sts);
|
||||||
sprintf(smlctimestamp, "%02d:%02d:%02d.%09d", tp->tm_hour, tp->tm_min, tp->tm_sec, sts.tv_nsec);
|
sprintf(smlctimestamp, "%02d:%02d:%02d.%09ld", tp->tm_hour, tp->tm_min, tp->tm_sec, sts.tv_nsec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (device) {
|
switch (device) {
|
||||||
@@ -320,20 +312,13 @@ int devsmlc (int class, int func, int device) {
|
|||||||
|
|
||||||
if (!inited) {
|
if (!inited) {
|
||||||
FILE *cfgfile;
|
FILE *cfgfile;
|
||||||
char devname[32];
|
|
||||||
int lc;
|
|
||||||
int tempport;
|
|
||||||
struct hostent* host;
|
struct hostent* host;
|
||||||
|
int lc;
|
||||||
char *p;
|
char *p;
|
||||||
|
char tcpaddr[MAXHOSTLEN + 1];
|
||||||
|
int tempport;
|
||||||
|
|
||||||
#if DEBUG
|
smlclogflush(); // initialize log buffer for BSC frames
|
||||||
smlclog = fopen("smlc.log", "wt");
|
|
||||||
if (smlclog == NULL) {
|
|
||||||
fprintf(stderr, "Failed to create smlclog.txt - aborting\n");
|
|
||||||
fatal(NULL);
|
|
||||||
}
|
|
||||||
smlclogflush(); // initialize log buffer
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* initially, we don't know about any SMLC boards */
|
/* initially, we don't know about any SMLC boards */
|
||||||
|
|
||||||
@@ -371,57 +356,54 @@ int devsmlc (int class, int func, int device) {
|
|||||||
while (fgets(buf, sizeof(buf), cfgfile) != NULL) {
|
while (fgets(buf, sizeof(buf), cfgfile) != NULL) {
|
||||||
int n;
|
int n;
|
||||||
lc++;
|
lc++;
|
||||||
buf[sizeof(devname)] = 0; /* don't let sscanf overwrite anything */
|
buf[sizeof(tcpaddr)] = 0; /* don't let sscanf overwrite anything */
|
||||||
buf[strlen(buf) - 1] = 0; /* remove trailing newline */
|
buf[strlen(buf) - 1] = 0; /* remove trailing newline */
|
||||||
if (buf[0] == '\0' || buf[0] == ';' || buf[0] == '#')
|
if (buf[0] == '\0' || buf[0] == ';' || buf[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
n = sscanf(buf, "%d %s", &i, devname);
|
n = sscanf(buf, "%d %s", &i, tcpaddr);
|
||||||
if (n != 2) {
|
if (n != 2) {
|
||||||
fprintf(stderr, "Can't parse smlc.cfg line #%d: %s\n", lc, buf);
|
fprintf(stderr, "smlc.cfg[%d] Can't parse: %s\n", lc, buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i < 0 || i >= SMLC_MAXLINES) {
|
if (i < 0 || i >= SMLC_MAXLINES) {
|
||||||
fprintf(stderr, "Line # %d out of range in smlc.cfg at line #%d: %s\n", i, lc, buf);
|
fprintf(stderr, "smlc.cfg[%d] SMLC line # %d out of range: %s\n", lc, i, buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
|
||||||
fprintf(smlclog, "%s Line %d, SMLC line %d set to device %s\n", smlctimestamp, lc, i, devname);
|
|
||||||
#endif
|
|
||||||
dx = i / SMLC_LINESPERBOARD;
|
dx = i / SMLC_LINESPERBOARD;
|
||||||
lx = i % SMLC_LINESPERBOARD;
|
lx = i % SMLC_LINESPERBOARD;
|
||||||
if (strlen(devname) > MAXHOSTLEN) {
|
if (strlen(tcpaddr) > MAXHOSTLEN) {
|
||||||
fprintf(stderr, "Line %d of smlc.cfg ignored: IP address too long\n", lc);
|
fprintf(stderr, "smlc.cfg[%d] IP address too long: %s\n", lc, buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tempport = 0;
|
tempport = 0;
|
||||||
if ((p=strtok(devname, PDELIM)) != NULL) {
|
host = NULL;
|
||||||
host = gethostbyname(p);
|
p = index(tcpaddr, ':');
|
||||||
|
if (p != NULL) {
|
||||||
|
*p++ = '\0';
|
||||||
|
host = gethostbyname(tcpaddr);
|
||||||
if (host == NULL) {
|
if (host == NULL) {
|
||||||
fprintf(stderr, "Line %d of smlc.cfg ignored: can't resolve IP address %s\n", lc, p);
|
fprintf(stderr, "smlc.cfg[%d] Can't resolve IP address of %s\n", lc, tcpaddr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((p=strtok(NULL, DELIM)) != NULL) {
|
tempport = atoi(p);
|
||||||
tempport = atoi(p);
|
} else {
|
||||||
if (tempport < 1 || tempport > 65000) {
|
tempport = atoi(tcpaddr);
|
||||||
fprintf(stderr, "Line %d of smlc.cfg ignored: port number %d out of range 1-65000\n", tempport, lc);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (tempport == 0) {
|
if (tempport == 0) {
|
||||||
fprintf(stderr, "Line %d of smlc.cfg ignored: no IP address or port number specified\n", lc);
|
fprintf(stderr, "smlc.cfg[%d] No IP address or port number specified\n", lc);
|
||||||
|
continue;
|
||||||
|
} else if (tempport < 1 || tempport > 65535) {
|
||||||
|
fprintf(stderr, "smlc.cfg[%d] Port number %d out of range 1-65535\n", lc, tempport);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
dc[dx].plines[lx].remoteID = (char *)malloc(32);
|
dc[dx].plines[lx].remoteID = (char *)malloc(32);
|
||||||
hostaddr = ntohl(*(unsigned int *)host->h_addr);
|
hostaddr = (host != NULL) ? ntohl(*(unsigned int *)host->h_addr) : 0;
|
||||||
sprintf(dc[dx].plines[lx].remoteID, "%d.%d.%d.%d:%d", (hostaddr >> 24) & 0xff, (hostaddr >> 16) & 0xff,
|
sprintf(dc[dx].plines[lx].remoteID, "%d.%d.%d.%d:%d", (hostaddr >> 24) & 0xff, (hostaddr >> 16) & 0xff,
|
||||||
(hostaddr >> 8) & 0xff, hostaddr & 0xff, tempport);
|
(hostaddr >> 8) & 0xff, hostaddr & 0xff, tempport);
|
||||||
dc[dx].plines[lx].host = hostaddr;
|
dc[dx].plines[lx].host = hostaddr;
|
||||||
dc[dx].plines[lx].port = tempport;
|
dc[dx].plines[lx].port = tempport;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s smlc.cfg[%d] controller '%02o, line %d, TCP address %s\n", smlctimestamp, lc, dx + 050, lx,
|
||||||
fprintf(smlclog, "%s TCP address, host=%x, port=%d, controller=%d, line=%d\n", smlctimestamp, dc[dx].plines[lx].host,
|
dc[dx].plines[lx].remoteID);
|
||||||
tempport, dx, lx);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
fclose(cfgfile);
|
fclose(cfgfile);
|
||||||
}
|
}
|
||||||
@@ -445,40 +427,30 @@ int devsmlc (int class, int func, int device) {
|
|||||||
switch (func) {
|
switch (func) {
|
||||||
|
|
||||||
case 000: // enable high-speed SMLC clock
|
case 000: // enable high-speed SMLC clock
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OCP '%02o%02o enable high-speed clock\n", smlctimestamp, func, device);
|
||||||
fprintf(smlclog, "%s OCP '%02o%02o enable high-speed clock\n", smlctimestamp, func, device);
|
|
||||||
#endif
|
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 013: // acknowledge and clear interrupt
|
case 013: // acknowledge and clear interrupt
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OCP '%02o%02o acknowledge and clear interrupt\n", smlctimestamp, func, device);
|
||||||
fprintf(smlclog, "%s OCP '%02o%02o acknowledge and clear interrupt\n", smlctimestamp, func, device);
|
|
||||||
#endif
|
|
||||||
dc[dx].intstate = SMLC_NOTINTERRUPTING;
|
dc[dx].intstate = SMLC_NOTINTERRUPTING;
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 015: // enable interrupts
|
case 015: // enable interrupts
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OCP '%02o%02o enable interrupts\n", smlctimestamp, func, device);
|
||||||
fprintf(smlclog, "%s OCP '%02o%02o enable interrupts\n", smlctimestamp, func, device);
|
|
||||||
#endif
|
|
||||||
dc[dx].intenabled = 1;
|
dc[dx].intenabled = 1;
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 016: // disable interrupts
|
case 016: // disable interrupts
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OCP '%02o%02o disable interrupts\n", smlctimestamp, func, device);
|
||||||
fprintf(smlclog, "%s OCP '%02o%02o disable interrupts\n", smlctimestamp, func, device);
|
|
||||||
#endif
|
|
||||||
dc[dx].intenabled = 0;
|
dc[dx].intenabled = 0;
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 017: // initialize controller
|
case 017: // initialize controller
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OCP '%02o%02o initialize controller\n", smlctimestamp, func, device);
|
||||||
fprintf(smlclog, "%s OCP '%02o%02o initialize controller\n", smlctimestamp, func, device);
|
|
||||||
#endif
|
|
||||||
dc[dx].intvector = 0;
|
dc[dx].intvector = 0;
|
||||||
dc[dx].intenabled = 0;
|
dc[dx].intenabled = 0;
|
||||||
dc[dx].intstate = SMLC_NOTINTERRUPTING;
|
dc[dx].intstate = SMLC_NOTINTERRUPTING;
|
||||||
@@ -534,9 +506,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
TRACE(T_INST, " SKS '%02o%02o\n", func, device);
|
TRACE(T_INST, " SKS '%02o%02o\n", func, device);
|
||||||
|
|
||||||
if (func == 004) { /* skip if not interrupting */
|
if (func == 004) { /* skip if not interrupting */
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s SKS '02%02o skip if not interrupting, state is %s\n", smlctimestamp, device, intstates[dc[dx].intstate]);
|
||||||
fprintf(smlclog, "%s SKS '02%02o skip if not interrupting, state is %s\n", smlctimestamp, device, intstates[dc[dx].intstate]);
|
|
||||||
#endif
|
|
||||||
if (dc[dx].intstate == SMLC_INTERRUPTING) {
|
if (dc[dx].intstate == SMLC_INTERRUPTING) {
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
}
|
}
|
||||||
@@ -564,16 +534,12 @@ int devsmlc (int class, int func, int device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
putcrs16(A, data);
|
putcrs16(A, data);
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s INA '00%02o input status returns 0x%04x\n", smlctimestamp, device, data);
|
||||||
fprintf(smlclog, "%s INA '00%02o input status returns 0x%04x\n", smlctimestamp, device, data);
|
|
||||||
#endif
|
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
|
|
||||||
} else if (func == 011) { /* report device ID */
|
} else if (func == 011) { /* report device ID */
|
||||||
putcrs16(A, SMLC_DEVICEID);
|
putcrs16(A, SMLC_DEVICEID);
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s INA '11%02o report device ID returns 0x%04x\n", smlctimestamp, device, getcrs16(A));
|
||||||
fprintf(smlclog, "%s INA '11%02o report device ID returns 0x%04x\n", smlctimestamp, device, getcrs16(A));
|
|
||||||
#endif
|
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -595,9 +561,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
data = getcrs16(A);
|
data = getcrs16(A);
|
||||||
dc[dx].fncode = data >> 8;
|
dc[dx].fncode = data >> 8;
|
||||||
dc[dx].lineno = data & 0377;
|
dc[dx].lineno = data & 0377;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '00%02o set function/line '%03o/'%03o\n", smlctimestamp, device, dc[dx].fncode, dc[dx].lineno);
|
||||||
fprintf(smlclog, "%s OTA '00%02o set function/line '%03o/'%03o\n", smlctimestamp, device, dc[dx].fncode, dc[dx].lineno);
|
|
||||||
#endif
|
|
||||||
switch (dc[dx].fncode) {
|
switch (dc[dx].fncode) {
|
||||||
|
|
||||||
case 000: // set modem controls
|
case 000: // set modem controls
|
||||||
@@ -627,15 +591,11 @@ int devsmlc (int class, int func, int device) {
|
|||||||
switch (dc[dx].fncode) {
|
switch (dc[dx].fncode) {
|
||||||
|
|
||||||
case 000: // set modem controls
|
case 000: // set modem controls
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set modem controls '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set modem controls '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
TRACE(T_SMLC, "%s DTR: %d, RTS: %d\n", smlctimestamp, data & 1, (data & 2) == 1);
|
||||||
fprintf(smlclog, "%s DTR: %d, RTS: %d\n", smlctimestamp, data & 1, (data & 2) == 1);
|
|
||||||
#endif
|
|
||||||
sp->dtr = data & 1;
|
sp->dtr = data & 1;
|
||||||
if ((data & 1) == 0 && lp->fd != -1) {
|
if ((data & 1) == 0 && lp->fd != -1) {
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s close connection to %s\n", smlctimestamp, lp->remoteID);
|
||||||
fprintf(smlclog, "%s close connection to %s\n", smlctimestamp, lp->remoteID);
|
|
||||||
#endif
|
|
||||||
close(lp->fd);
|
close(lp->fd);
|
||||||
lp->fd = -1;
|
lp->fd = -1;
|
||||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
lp->connstate = SMLC_STATEDISCONNECTED;
|
||||||
@@ -647,9 +607,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
case 010: // set special character
|
case 010: // set special character
|
||||||
i = (data >> 8) & 0xff;
|
i = (data >> 8) & 0xff;
|
||||||
ch = data & 0xff;
|
ch = data & 0xff;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set special character %d <%02x>\n", smlctimestamp, device, dc[dx].lineno, i, ch);
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set special character %d <%02x>\n", smlctimestamp, device, dc[dx].lineno, i, ch);
|
|
||||||
#endif
|
|
||||||
if (i < SMLC_MAXSPCHARS) {
|
if (i < SMLC_MAXSPCHARS) {
|
||||||
sp->spchars[i] = ch;
|
sp->spchars[i] = ch;
|
||||||
} else {
|
} else {
|
||||||
@@ -660,30 +618,26 @@ int devsmlc (int class, int func, int device) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 012: // set configuration word
|
case 012: // set configuration word
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set configuration word 0x%04x\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set configuration word 0x%04x\n", smlctimestamp, device, dc[dx].lineno, data);
|
|
||||||
#endif
|
|
||||||
sp->configword = data;
|
sp->configword = data;
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 014: // set primary I/O channel
|
case 014: // set primary I/O channel
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set primary I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set primary I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
|
||||||
#endif
|
|
||||||
sp->dmcprimarycount = (data >> 12) + 1;
|
sp->dmcprimarycount = (data >> 12) + 1;
|
||||||
sp->dmcprimaryidx = 0;
|
sp->dmcprimaryidx = 0;
|
||||||
sp->dmcprimary = data & 0x7fe;
|
sp->dmcprimary = data & 0x7fe;
|
||||||
if (data != 0) {
|
if (data != 0) {
|
||||||
if ((data & 04000) == 0) fatal("Can't run SMLC in DMA mode!");
|
if ((data & 04000) == 0) fatal("Can't run SMLC in DMA mode!");
|
||||||
#if DEBUG
|
#ifndef NOTRACE
|
||||||
fprintf(smlclog, "%s %d buffers\n", smlctimestamp, sp->dmcprimarycount);
|
TRACE(T_SMLC, "%s %d buffers\n", smlctimestamp, sp->dmcprimarycount);
|
||||||
for (i = 0; i < sp->dmcprimarycount; i++) {
|
for (i = 0; i < sp->dmcprimarycount; i++) {
|
||||||
dmcpair = get32io ((data & 0x7fe) + (i * 2));
|
dmcpair = get32io ((data & 0x7fe) + (i * 2));
|
||||||
dmcbufbegea = dmcpair >> 16;
|
dmcbufbegea = dmcpair >> 16;
|
||||||
dmcbufendea = dmcpair & 0xffff;
|
dmcbufendea = dmcpair & 0xffff;
|
||||||
dmcnw = (dmcbufendea - dmcbufbegea) + 1;
|
dmcnw = (dmcbufendea - dmcbufbegea) + 1;
|
||||||
fprintf(smlclog, "%s %d: next '%06o, last '%06o, words %d\n", smlctimestamp, i, dmcbufbegea, dmcbufendea, dmcnw);
|
TRACE(T_SMLC, "%s %d: next '%06o, last '%06o, words %d\n", smlctimestamp, i, dmcbufbegea, dmcbufendea, dmcnw);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -691,10 +645,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 015: // enable
|
case 015: // enable
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o enable '%06o (%s %s)\n", smlctimestamp, device, dc[dx].lineno, data,
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o enable '%06o (%s %s)\n", smlctimestamp, device, dc[dx].lineno, data,
|
|
||||||
sx ? "xmit" : "recv", (data & 1) ? "on" : "off");
|
sx ? "xmit" : "recv", (data & 1) ? "on" : "off");
|
||||||
#endif
|
|
||||||
sp->enabled = data & 1;
|
sp->enabled = data & 1;
|
||||||
if (sp->enabled) devpoll[device] = 1;
|
if (sp->enabled) devpoll[device] = 1;
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
@@ -706,22 +658,20 @@ int devsmlc (int class, int func, int device) {
|
|||||||
* this OTA function. Consequently, this emulation module does not currently implement any logic to alternate
|
* this OTA function. Consequently, this emulation module does not currently implement any logic to alternate
|
||||||
* storing recceived data between the primary and backup channels.
|
* storing recceived data between the primary and backup channels.
|
||||||
*/
|
*/
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set backup I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set backup I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
|
||||||
#endif
|
|
||||||
sp->dmcbackupcount = (data >> 12) + 1;
|
sp->dmcbackupcount = (data >> 12) + 1;
|
||||||
sp->dmcbackupidx = 0;
|
sp->dmcbackupidx = 0;
|
||||||
sp->dmcbackup = data & 0x7fe;
|
sp->dmcbackup = data & 0x7fe;
|
||||||
if (data != 0) {
|
if (data != 0) {
|
||||||
if ((data & 04000) == 0) fatal("Can't run SMLC in DMA mode!");
|
if ((data & 04000) == 0) fatal("Can't run SMLC in DMA mode!");
|
||||||
#if DEBUG
|
#ifndef NOTRACE
|
||||||
fprintf(smlclog, "%s %d buffers\n", smlctimestamp, sp->dmcbackupcount);
|
TRACE(T_SMLC, "%s %d buffers\n", smlctimestamp, sp->dmcbackupcount);
|
||||||
for (i = 0; i < sp->dmcbackupcount; i++) {
|
for (i = 0; i < sp->dmcbackupcount; i++) {
|
||||||
dmcpair = get32io ((data & 0x7fe) + (i * 2));
|
dmcpair = get32io ((data & 0x7fe) + (i * 2));
|
||||||
dmcbufbegea = dmcpair >> 16;
|
dmcbufbegea = dmcpair >> 16;
|
||||||
dmcbufendea = dmcpair & 0xffff;
|
dmcbufendea = dmcpair & 0xffff;
|
||||||
dmcnw = (dmcbufendea - dmcbufbegea) + 1;
|
dmcnw = (dmcbufendea - dmcbufbegea) + 1;
|
||||||
fprintf(smlclog, "%s %d: next '%06o, last '%06o, words %d\n", smlctimestamp, i, dmcbufbegea, dmcbufendea, dmcnw);
|
TRACE(T_SMLC, "%s %d: next '%06o, last '%06o, words %d\n", smlctimestamp, i, dmcbufbegea, dmcbufendea, dmcnw);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -729,9 +679,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 017: // set status channel
|
case 017: // set status channel
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set status channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set status channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
|
||||||
#endif
|
|
||||||
if (!(data & 04000) && data != 0)
|
if (!(data & 04000) && data != 0)
|
||||||
fatal("Can't run SMLC in DMA mode!");
|
fatal("Can't run SMLC in DMA mode!");
|
||||||
if (lx != 0 || sx != 0) {
|
if (lx != 0 || sx != 0) {
|
||||||
@@ -740,9 +688,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
}
|
}
|
||||||
dc[dx].dmcstatus = data & 0x7fe;
|
dc[dx].dmcstatus = data & 0x7fe;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s next %06o, last %06o\n", smlctimestamp, get32io(dc[dx].dmcstatus) >> 16, get32io(dc[dx].dmcstatus) & 0xffff);
|
||||||
fprintf(smlclog, "%s next %06o, last %06o\n", smlctimestamp, get32io(dc[dx].dmcstatus) >> 16, get32io(dc[dx].dmcstatus) & 0xffff);
|
|
||||||
#endif
|
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -754,9 +700,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 016: // set interrupt vector
|
case 016: // set interrupt vector
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s OTA '16%02o set interrupt vector '%06o\n", smlctimestamp, device, getcrs16(A));
|
||||||
fprintf(smlclog, "%s OTA '16%02o set interrupt vector '%06o\n", smlctimestamp, device, getcrs16(A));
|
|
||||||
#endif
|
|
||||||
dc[dx].intvector = getcrs16(A);
|
dc[dx].intvector = getcrs16(A);
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
break;
|
break;
|
||||||
@@ -785,9 +729,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
} else {
|
} else {
|
||||||
gv.intvec = dc[dx].intvector;
|
gv.intvec = dc[dx].intvector;
|
||||||
dc[dx].intstate = SMLC_INTERRUPTING;
|
dc[dx].intstate = SMLC_INTERRUPTING;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Raise interrupt on device '%02o\n", smlctimestamp, device);
|
||||||
fprintf(smlclog, "%s Raise interrupt on device '%02o\n", smlctimestamp, device);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -798,23 +740,41 @@ int devsmlc (int class, int func, int device) {
|
|||||||
|
|
||||||
for (lx = 0; lx < SMLC_LINESPERBOARD; lx++) {
|
for (lx = 0; lx < SMLC_LINESPERBOARD; lx++) {
|
||||||
lp = &dc[dx].plines[lx];
|
lp = &dc[dx].plines[lx];
|
||||||
if (lp->host == 0) continue;
|
if (lp->port == 0) continue;
|
||||||
switch (lp->connstate) {
|
switch (lp->connstate) {
|
||||||
|
|
||||||
case SMLC_STATEDISCONNECTED:
|
case SMLC_STATEDISCONNECTED:
|
||||||
if (lp->nextconntime <= currenttime && lp->slines[SMLC_RECVIX].dtr != 0) {
|
if (lp->host != 0) {
|
||||||
|
//
|
||||||
|
// Workstation mode.
|
||||||
|
//
|
||||||
|
// Periodically attempt to create a connection to the remote host, when
|
||||||
|
// the DTR modem signal is up.
|
||||||
|
//
|
||||||
|
if (lp->slines[SMLC_RECVIX].dtr == 0 || lp->nextconntime > currenttime) continue;
|
||||||
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, "Failed to create socket for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
fprintf(stderr, "Failed to create socket for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
}
|
}
|
||||||
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optenable, sizeof(optenable));
|
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optenable, sizeof(optenable)) == -1) {
|
||||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
fprintf(stderr, "Failed to set socket option SO_KEEPALICE for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
bzero((char *) &raddr, sizeof(raddr));
|
fatal(NULL);
|
||||||
raddr.sin_family = AF_INET;
|
}
|
||||||
raddr.sin_addr.s_addr = htonl(dc[dx].plines[lx].host);
|
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
||||||
raddr.sin_port = htons(dc[dx].plines[lx].port);
|
fprintf(stderr, "Failed to get flags for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
rc = connect(fd, (struct sockaddr *)&raddr, sizeof(raddr));
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
if (fcntl(fd, F_SETFL, flags) == -1) {
|
||||||
|
fprintf(stderr, "Failed to set flags for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
bzero((char *) &addr, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = htonl(lp->host);
|
||||||
|
addr.sin_port = htons(lp->port);
|
||||||
|
rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
lp->connstate = SMLC_STATECONNECTING;
|
lp->connstate = SMLC_STATECONNECTING;
|
||||||
if (rc < 0 && errno != EINPROGRESS) {
|
if (rc < 0 && errno != EINPROGRESS) {
|
||||||
fprintf(stderr, "Failed to create connection to %s for SMLC line %d\n", lp->remoteID,
|
fprintf(stderr, "Failed to create connection to %s for SMLC line %d\n", lp->remoteID,
|
||||||
@@ -824,18 +784,67 @@ int devsmlc (int class, int func, int device) {
|
|||||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
lp->connstate = SMLC_STATEDISCONNECTED;
|
||||||
break;
|
break;
|
||||||
} else { // connection in progress
|
} else { // connection in progress
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Connection initiated to %s for SMLC line %d\n", smlctimestamp, lp->remoteID,
|
||||||
fprintf(smlclog, "%s Connection initiated to %s for SMLC line %d\n", smlctimestamp, lp->remoteID,
|
|
||||||
(dx * SMLC_LINESPERBOARD) + lx);
|
(dx * SMLC_LINESPERBOARD) + lx);
|
||||||
#endif
|
|
||||||
lp->fd = fd;
|
lp->fd = fd;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Host mode.
|
||||||
|
//
|
||||||
|
// Begin listening for connections.
|
||||||
|
//
|
||||||
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "Failed to create socket for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optenable, sizeof(optenable)) == -1) {
|
||||||
|
fprintf(stderr, "Failed to set socket option SO_REUSEADDR for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.sin_port = htons(lp->port);
|
||||||
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||||
|
fprintf(stderr, "Failed to bind to port %d for SMLC line %d\n", lp->port, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
if (listen(fd, 1) == -1) {
|
||||||
|
fprintf(stderr, "Failed to listen on port %d for SMLC line %d\n", lp->port, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
||||||
|
fprintf(stderr, "Failed to get flags for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
if (fcntl(fd, F_SETFL, flags) == -1) {
|
||||||
|
fprintf(stderr, "Failed to set flags for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
lp->fd = fd;
|
||||||
|
lp->connstate = SMLC_STATECONNECTING;
|
||||||
|
TRACE(T_SMLC, "%s Listening for connections on %s for SMLC line %d\n", smlctimestamp, lp->remoteID,
|
||||||
|
(dx * SMLC_LINESPERBOARD) + lx);
|
||||||
}
|
}
|
||||||
/* fall through when no error has occurred */
|
if (lp->connstate != SMLC_STATECONNECTING) break;
|
||||||
|
|
||||||
case SMLC_STATECONNECTING:
|
case SMLC_STATECONNECTING:
|
||||||
FD_SET(lp->fd, &writefds);
|
if (lp->host != 0) {
|
||||||
if (lp->fd > maxfd) maxfd = lp->fd;
|
//
|
||||||
|
// Workstation mode. Connection is complete when socket is writable.
|
||||||
|
//
|
||||||
|
FD_SET(lp->fd, &writefds);
|
||||||
|
if (lp->fd > maxfd) maxfd = lp->fd;
|
||||||
|
} else if (lp->slines[SMLC_RECVIX].dtr != 0) {
|
||||||
|
//
|
||||||
|
// Host mode. Connection request received when socket is readable.
|
||||||
|
// However, test for requests only when DTR modem signal is up.
|
||||||
|
//
|
||||||
|
FD_SET(lp->fd, &readfds);
|
||||||
|
if (lp->fd > maxfd) maxfd = lp->fd;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SMLC_STATECONNECTED:
|
case SMLC_STATECONNECTED:
|
||||||
@@ -863,11 +872,9 @@ int devsmlc (int class, int func, int device) {
|
|||||||
if (dmcnw <= 0) {
|
if (dmcnw <= 0) {
|
||||||
sp->dmcprimaryidx += 1;
|
sp->dmcprimaryidx += 1;
|
||||||
} else {
|
} else {
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Line %d on device '%02o send to %s from channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
||||||
fprintf(smlclog, "%s Line %d on device '%02o send to %s from channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
|
||||||
sp->dmcprimary);
|
sp->dmcprimary);
|
||||||
fprintf(smlclog, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
TRACE(T_SMLC, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
||||||
#endif
|
|
||||||
n = 0;
|
n = 0;
|
||||||
while (n < dmcnw && np + 1 < ep) {
|
while (n < dmcnw && np + 1 < ep) {
|
||||||
word = get16io(dmcbufbegea);
|
word = get16io(dmcbufbegea);
|
||||||
@@ -876,10 +883,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
*np++ = word & 0377;
|
*np++ = word & 0377;
|
||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s %d words transferred to output buffer\n", smlctimestamp, n);
|
||||||
fprintf(smlclog, "%s %d words transferred to output buffer\n", smlctimestamp, n);
|
TRACE(T_SMLC, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
||||||
fprintf(smlclog, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
|
||||||
#endif
|
|
||||||
put16io(dmcbufbegea, sp->dmcprimary + (sp->dmcprimaryidx * 2));
|
put16io(dmcbufbegea, sp->dmcprimary + (sp->dmcprimaryidx * 2));
|
||||||
if (n == dmcnw) {
|
if (n == dmcnw) {
|
||||||
status = SMLC_EOR | SMLC_XMIT;
|
status = SMLC_EOR | SMLC_XMIT;
|
||||||
@@ -925,7 +930,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
|
|
||||||
for (lx = 0; lx < SMLC_LINESPERBOARD; lx++) {
|
for (lx = 0; lx < SMLC_LINESPERBOARD; lx++) {
|
||||||
lp = &dc[dx].plines[lx];
|
lp = &dc[dx].plines[lx];
|
||||||
if (lp->host == 0) continue;
|
if (lp->port == 0) continue;
|
||||||
switch (lp->connstate) {
|
switch (lp->connstate) {
|
||||||
|
|
||||||
case SMLC_STATECONNECTING:
|
case SMLC_STATECONNECTING:
|
||||||
@@ -934,10 +939,7 @@ int devsmlc (int class, int func, int device) {
|
|||||||
rc = getsockopt(lp->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen);
|
rc = getsockopt(lp->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "Failed to get socket status for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
fprintf(stderr, "Failed to get socket status for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
close(lp->fd);
|
fatal(NULL);
|
||||||
lp->fd = -1;
|
|
||||||
lp->nextconntime = currenttime + SMLC_CONNECTINTERVAL;
|
|
||||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
|
||||||
} else if (optval != 0) { // connection failed
|
} else if (optval != 0) { // connection failed
|
||||||
fprintf(stderr, "Failed to create connection to %s for SMLC line %d\n", lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
fprintf(stderr, "Failed to create connection to %s for SMLC line %d\n", lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
close(lp->fd);
|
close(lp->fd);
|
||||||
@@ -945,47 +947,72 @@ int devsmlc (int class, int func, int device) {
|
|||||||
lp->nextconntime = currenttime + SMLC_CONNECTINTERVAL;
|
lp->nextconntime = currenttime + SMLC_CONNECTINTERVAL;
|
||||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
lp->connstate = SMLC_STATEDISCONNECTED;
|
||||||
} else {
|
} else {
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Connection created to %s for SMLC line %d\n", smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
fprintf(smlclog, "%s Connection created to %s for SMLC line %d\n", smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
|
||||||
#endif
|
|
||||||
lp->connstate = SMLC_STATECONNECTED;
|
lp->connstate = SMLC_STATECONNECTED;
|
||||||
lp->recvstate = SMLC_STATERCVSYN;
|
lp->recvstate = SMLC_STATERCVSYN;
|
||||||
lp->starting = 0;
|
}
|
||||||
lp->naksent = 0;
|
} else if (FD_ISSET(lp->fd, &readfds)) {
|
||||||
lp->slines[SMLC_RECVIX].buf.in = 0;
|
addrlen = sizeof(addr);
|
||||||
lp->slines[SMLC_RECVIX].buf.out = 0;
|
fd = accept(lp->fd, (struct sockaddr *)&addr, &addrlen);
|
||||||
lp->slines[SMLC_XMITIX].buf.in = 0;
|
if (fd >= 0) {
|
||||||
lp->slines[SMLC_XMITIX].buf.out = 0;
|
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optenable, sizeof(optenable)) == -1) {
|
||||||
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT | SMLC_DSR_BIT | SMLC_CTS_BIT | SMLC_DCD_BIT | SMLC_SQ_BIT);
|
fprintf(stderr, "Failed to set socket option SO_KEEPALICE for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
||||||
|
fprintf(stderr, "Failed to get flags for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
if (fcntl(fd, F_SETFL, flags) == -1) {
|
||||||
|
fprintf(stderr, "Failed to set flags for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
|
close(lp->fd);
|
||||||
|
lp->fd = fd;
|
||||||
|
lp->connstate = SMLC_STATECONNECTED;
|
||||||
|
lp->recvstate = SMLC_STATERCVSOH;
|
||||||
|
strcpy(lp->remoteID, inet_ntoa(addr.sin_addr));
|
||||||
|
TRACE(T_SMLC, "%s Connection accepted from %s for SMLC line %d\n", smlctimestamp, lp->remoteID,
|
||||||
|
(dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TRACE(T_SMLC, "%s Spurious connection attempt on SMLC line %d\n", smlctimestamp, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lp->connstate != SMLC_STATECONNECTED)
|
if (lp->connstate == SMLC_STATECONNECTED) {
|
||||||
break;
|
lp->starting = 0;
|
||||||
|
lp->naksent = 0;
|
||||||
|
lp->slines[SMLC_RECVIX].buf.in = 0;
|
||||||
|
lp->slines[SMLC_RECVIX].buf.out = 0;
|
||||||
|
lp->slines[SMLC_XMITIX].buf.in = 0;
|
||||||
|
lp->slines[SMLC_XMITIX].buf.out = 0;
|
||||||
|
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT | SMLC_DSR_BIT | SMLC_CTS_BIT | SMLC_DCD_BIT | SMLC_SQ_BIT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case SMLC_STATECONNECTED:
|
case SMLC_STATECONNECTED:
|
||||||
sp = &lp->slines[SMLC_RECVIX];
|
sp = &lp->slines[SMLC_RECVIX];
|
||||||
if (FD_ISSET(lp->fd, &readfds)) {
|
if (FD_ISSET(lp->fd, &readfds)) {
|
||||||
n = read(lp->fd, &sp->buf.data[sp->buf.in], sizeof(sp->buf.data) - sp->buf.in);
|
n = read(lp->fd, &sp->buf.data[sp->buf.in], sizeof(sp->buf.data) - sp->buf.in);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
#if DEBUG
|
#ifndef NOTRACE
|
||||||
fprintf(smlclog, "%s Line %d on device '%02o received %d bytes from %s:\n", smlctimestamp, lx, device, n, lp->remoteID);
|
TRACE(T_SMLC, "%s Line %d on device '%02o received %d bytes from %s:\n", smlctimestamp, lx, device, n, lp->remoteID);
|
||||||
smlclogbytes(&sp->buf.data[sp->buf.in], n);
|
smlclogbytes(&sp->buf.data[sp->buf.in], n);
|
||||||
smlclogflush();
|
smlclogflush();
|
||||||
#endif
|
#endif
|
||||||
sp->buf.in += n;
|
sp->buf.in += n;
|
||||||
} else if (n < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)) {
|
} else if (n < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)) {
|
||||||
n = 0;
|
n = 0;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s read from %s for line %d returned errno %d (ignored)\n",
|
||||||
fprintf(smlclog, "%s recv from %s for line %d returned errno %d (ignored)\n",
|
|
||||||
smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx, errno);
|
smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx, errno);
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
#if DEBUG
|
#ifndef NOTRACE
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(smlclog, "%s recv from %s for line %d failed with errno %d\n",
|
TRACE(T_SMLC, "%s read from %s for line %d failed with errno %d\n",
|
||||||
smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx, errno);
|
smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx, errno);
|
||||||
} else {
|
} else {
|
||||||
fprintf(smlclog, "%s recv from %s for line %d returned EOF\n", smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
TRACE(T_SMLC, "%s read from %s for line %d returned EOF\n", smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
lp->connstate = SMLC_STATEDISCONNECTING;
|
lp->connstate = SMLC_STATEDISCONNECTING;
|
||||||
@@ -1007,17 +1034,15 @@ int devsmlc (int class, int func, int device) {
|
|||||||
sp->dmcprimaryidx += 1;
|
sp->dmcprimaryidx += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Line %d on device '%02o receive from %s to channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
||||||
fprintf(smlclog, "%s Line %d on device '%02o receive from %s to channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
|
||||||
sp->dmcprimary);
|
sp->dmcprimary);
|
||||||
fprintf(smlclog, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
TRACE(T_SMLC, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
||||||
#endif
|
|
||||||
maxbytes = dmcnw * 2;
|
maxbytes = dmcnw * 2;
|
||||||
n = 0;
|
n = 0;
|
||||||
dmcnw = 0;
|
dmcnw = 0;
|
||||||
status = 0;
|
status = 0;
|
||||||
isetb = 0;
|
isetb = 0;
|
||||||
while (n < maxbytes && np < ip) {
|
while (n < maxbytes && np < ip && status == 0) {
|
||||||
ch = *np++;
|
ch = *np++;
|
||||||
if (lp->recvstate == SMLC_STATERCVSYN) {
|
if (lp->recvstate == SMLC_STATERCVSYN) {
|
||||||
if (ch == SMLC_SYN) {
|
if (ch == SMLC_SYN) {
|
||||||
@@ -1030,10 +1055,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
lp->recvstate = SMLC_STATERCVSYN;
|
lp->recvstate = SMLC_STATERCVSYN;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s NAK received after sending NAK to %s for line %d\n", smlctimestamp, lp->remoteID,
|
||||||
fprintf(smlclog, "%s NAK received after sending NAK to %s for line %d\n", smlctimestamp, lp->remoteID,
|
|
||||||
(dx * SMLC_LINESPERBOARD) + lx);
|
(dx * SMLC_LINESPERBOARD) + lx);
|
||||||
#endif
|
|
||||||
lp->connstate = SMLC_STATEDISCONNECTING;
|
lp->connstate = SMLC_STATEDISCONNECTING;
|
||||||
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT);
|
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT);
|
||||||
devpoll[device] = 1; /* return ASAP */
|
devpoll[device] = 1; /* return ASAP */
|
||||||
@@ -1052,29 +1075,64 @@ int devsmlc (int class, int func, int device) {
|
|||||||
word = ch << 8;
|
word = ch << 8;
|
||||||
}
|
}
|
||||||
n += 1;
|
n += 1;
|
||||||
if (lp->recvstate == SMLC_STATERCVDLE) {
|
switch (lp->recvstate) {
|
||||||
|
case SMLC_STATERCVDLE:
|
||||||
lp->recvstate = SMLC_STATERCVCHAR;
|
lp->recvstate = SMLC_STATERCVCHAR;
|
||||||
if (ch == SMLC_ACK0) {
|
switch (ch) {
|
||||||
|
case SMLC_ACK0:
|
||||||
status |= SMLC_ENCODE_BIT | SMLC_ACK0_STATUS;
|
status |= SMLC_ENCODE_BIT | SMLC_ACK0_STATUS;
|
||||||
lp->recvstate = SMLC_STATERCVSYN;
|
lp->recvstate = SMLC_STATERCVSYN;
|
||||||
break;
|
break;
|
||||||
} else if (ch == SMLC_STX) {
|
case SMLC_STX:
|
||||||
status |= SMLC_ENCODE_BIT | SMLC_STX_STATUS;
|
status |= SMLC_ENCODE_BIT | SMLC_STX_STATUS;
|
||||||
break;
|
break;
|
||||||
} else if (ch == SMLC_ETB) {
|
case SMLC_ETB:
|
||||||
status |= SMLC_ENCODE_BIT | SMLC_ETB_STATUS;
|
status |= SMLC_ENCODE_BIT | SMLC_ETB_STATUS;
|
||||||
lp->recvstate = SMLC_STATERCVSYN;
|
lp->recvstate = SMLC_STATERCVSYN;
|
||||||
isetb = 1;
|
isetb = 1;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
// do nothing
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (ch == SMLC_DLE) {
|
break;
|
||||||
lp->recvstate = SMLC_STATERCVDLE;
|
case SMLC_STATERCVSOH:
|
||||||
|
if (ch == SMLC_SOH) {
|
||||||
|
status |= SMLC_ENCODE_BIT | SMLC_SOH_STATUS;
|
||||||
|
lp->recvstate = SMLC_STATERCVENQ;
|
||||||
|
} else {
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SMLC_STATERCVENQ:
|
||||||
|
if (ch == SMLC_ENQ) {
|
||||||
|
status |= SMLC_ENCODE_BIT | SMLC_ENQ_STATUS;
|
||||||
|
lp->recvstate = SMLC_STATERCVSYN;
|
||||||
|
} else if (ch == SMLC_SOH) {
|
||||||
|
status |= SMLC_ENCODE_BIT | SMLC_SOH_STATUS;
|
||||||
|
} else {
|
||||||
|
n = 0;
|
||||||
|
lp->recvstate = SMLC_STATERCVSOH;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SMLC_STATERCVCHAR:
|
||||||
|
if (ch == SMLC_DLE) {
|
||||||
|
lp->recvstate = SMLC_STATERCVDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Invalid recv state %d for SMLC line %d\n", lp->recvstate, (dx * SMLC_LINESPERBOARD) + lx);
|
||||||
|
fatal(NULL);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((n & 1) != 0) { // odd number of bytes processed, so store "incomplete" word, or back up one byte
|
if ((n & 1) != 0) { // odd number of bytes processed, so store "incomplete" word, or back up one byte
|
||||||
if (n < maxbytes
|
if (n < maxbytes
|
||||||
&& ((n > 1 && *(np - 1) == SMLC_ETB && *(np - 2) == SMLC_DLE)
|
&& (status & SMLC_ENCODE_BIT) != 0
|
||||||
|| (n == 1 && *(np - 1) == SMLC_NAK))) {
|
&& ( (status & SMLC_MASK_STATUS) == SMLC_ETB_STATUS
|
||||||
|
|| (status & SMLC_MASK_STATUS) == SMLC_SOH_STATUS
|
||||||
|
|| (status & SMLC_MASK_STATUS) == SMLC_ENQ_STATUS
|
||||||
|
|| (status & SMLC_MASK_STATUS) == SMLC_NAK_STATUS)) {
|
||||||
put16io(word, dmcbufbegea);
|
put16io(word, dmcbufbegea);
|
||||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||||
dmcnw += 1;
|
dmcnw += 1;
|
||||||
@@ -1085,10 +1143,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
}
|
}
|
||||||
put16io(dmcbufbegea, sp->dmcprimary + (sp->dmcprimaryidx * 2));
|
put16io(dmcbufbegea, sp->dmcprimary + (sp->dmcprimaryidx * 2));
|
||||||
sp->dmcprimaryidx += 1;
|
sp->dmcprimaryidx += 1;
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s %d words transferred from input buffer\n", smlctimestamp, dmcnw);
|
||||||
fprintf(smlclog, "%s %d words transferred from input buffer\n", smlctimestamp, dmcnw);
|
TRACE(T_SMLC, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
||||||
fprintf(smlclog, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
|
||||||
#endif
|
|
||||||
if (n == maxbytes) {
|
if (n == maxbytes) {
|
||||||
status |= SMLC_EOR;
|
status |= SMLC_EOR;
|
||||||
} else if (n > maxbytes) {
|
} else if (n > maxbytes) {
|
||||||
@@ -1117,8 +1173,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
lp->naksent = nbytes >= 5 && sp->buf.data[sp->buf.out + 4] == SMLC_NAK;
|
lp->naksent = nbytes >= 5 && sp->buf.data[sp->buf.out + 4] == SMLC_NAK;
|
||||||
n = write(lp->fd, &sp->buf.data[sp->buf.out], nbytes);
|
n = write(lp->fd, &sp->buf.data[sp->buf.out], nbytes);
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
#if DEBUG
|
#ifndef NOTRACE
|
||||||
fprintf(smlclog, "%s Line %d on device '%02o sent %d bytes to %s:\n", smlctimestamp, lx, device, n, lp->remoteID);
|
TRACE(T_SMLC, "%s Line %d on device '%02o sent %d bytes to %s:\n", smlctimestamp, lx, device, n, lp->remoteID);
|
||||||
smlclogbytes(&sp->buf.data[sp->buf.out], n);
|
smlclogbytes(&sp->buf.data[sp->buf.out], n);
|
||||||
smlclogflush();
|
smlclogflush();
|
||||||
#endif
|
#endif
|
||||||
@@ -1128,10 +1184,8 @@ int devsmlc (int class, int func, int device) {
|
|||||||
smlcaddstatus(&dc[dx], lx, SMLC_LCT | SMLC_XMIT);
|
smlcaddstatus(&dc[dx], lx, SMLC_LCT | SMLC_XMIT);
|
||||||
}
|
}
|
||||||
} else if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) {
|
} else if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) {
|
||||||
#if DEBUG
|
TRACE(T_SMLC, "%s Connection failed to %s for line %d with errno %d\n", smlctimestamp, lp->remoteID,
|
||||||
fprintf(smlclog, "%s Connection failed to %s for line %d with errno %d\n", smlctimestamp, lp->remoteID,
|
|
||||||
(dx * SMLC_LINESPERBOARD) + lx, errno);
|
(dx * SMLC_LINESPERBOARD) + lx, errno);
|
||||||
#endif
|
|
||||||
lp->connstate = SMLC_STATEDISCONNECTING;
|
lp->connstate = SMLC_STATEDISCONNECTING;
|
||||||
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT);
|
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT);
|
||||||
devpoll[device] = 1; /* return ASAP */
|
devpoll[device] = 1; /* return ASAP */
|
||||||
@@ -1155,7 +1209,6 @@ int devsmlc (int class, int func, int device) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
static unsigned char ebcdicToAscii[256] = {
|
static unsigned char ebcdicToAscii[256] = {
|
||||||
/* 00-07 */ 0x00, 0x01, 0x02, 0x03, 0x1a, 0x09, 0x1a, 0x7f,
|
/* 00-07 */ 0x00, 0x01, 0x02, 0x03, 0x1a, 0x09, 0x1a, 0x7f,
|
||||||
/* 08-0F */ 0x1a, 0x1a, 0x1a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
/* 08-0F */ 0x1a, 0x1a, 0x1a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
@@ -1193,14 +1246,16 @@ static unsigned char ebcdicToAscii[256] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void smlclogflush(void) {
|
static void smlclogflush(void) {
|
||||||
|
#ifndef NOTRACE
|
||||||
if (smlclogbytescol > 0) {
|
if (smlclogbytescol > 0) {
|
||||||
fputs(smlclogbuf, smlclog);
|
fputs(smlclogbuf, gv.tracefile);
|
||||||
fputc('\n', smlclog);
|
fputc('\n', gv.tracefile);
|
||||||
fflush(smlclog);
|
fflush(gv.tracefile);
|
||||||
}
|
}
|
||||||
smlclogbytescol = 0;
|
smlclogbytescol = 0;
|
||||||
memset(smlclogbuf, ' ', LogLineLength);
|
memset(smlclogbuf, ' ', LogLineLength);
|
||||||
smlclogbuf[LogLineLength] = '\0';
|
smlclogbuf[LogLineLength] = '\0';
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smlclogbytes(unsigned char *bytes, int len) {
|
static void smlclogbytes(unsigned char *bytes, int len) {
|
||||||
@@ -1211,24 +1266,27 @@ static void smlclogbytes(unsigned char *bytes, int len) {
|
|||||||
int hexCol;
|
int hexCol;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ascCol = AsciiColumn(smlclogbytescol);
|
#ifndef NOTRACE
|
||||||
hexCol = HexColumn(smlclogbytescol);
|
if (gv.traceflags & T_SMLC) {
|
||||||
|
ascCol = AsciiColumn(smlclogbytescol);
|
||||||
|
hexCol = HexColumn(smlclogbytescol);
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
b = bytes[i];
|
b = bytes[i];
|
||||||
ac = ebcdicToAscii[b];
|
ac = ebcdicToAscii[b];
|
||||||
if (ac < 0x20 || ac >= 0x7f) {
|
if (ac < 0x20 || ac >= 0x7f) {
|
||||||
ac = '.';
|
ac = '.';
|
||||||
}
|
}
|
||||||
sprintf(hex, "%02x", b);
|
sprintf(hex, "%02x", b);
|
||||||
memcpy(smlclogbuf + hexCol, hex, 2);
|
memcpy(smlclogbuf + hexCol, hex, 2);
|
||||||
hexCol += 3;
|
hexCol += 3;
|
||||||
smlclogbuf[ascCol++] = ac;
|
smlclogbuf[ascCol++] = ac;
|
||||||
if (++smlclogbytescol >= 16) {
|
if (++smlclogbytescol >= 16) {
|
||||||
smlclogflush();
|
smlclogflush();
|
||||||
ascCol = AsciiColumn(smlclogbytescol);
|
ascCol = AsciiColumn(smlclogbytescol);
|
||||||
hexCol = HexColumn(smlclogbytescol);
|
hexCol = HexColumn(smlclogbytescol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
22
em.1
22
em.1
@@ -145,6 +145,15 @@ on the host. Multiple trace types may be listed, separated by
|
|||||||
spaces. Tracing may be initially turned off by including the
|
spaces. Tracing may be initially turned off by including the
|
||||||
.I off
|
.I off
|
||||||
trace type.
|
trace type.
|
||||||
|
.PP
|
||||||
|
\fB-dolineclear\fR
|
||||||
|
.IP
|
||||||
|
Inject an XON (DC1, 0221) character and a line kill character into the
|
||||||
|
input buffers each time an AMLC line receives an incoming connection.
|
||||||
|
The system's configured line kill character is fetched from the
|
||||||
|
DEFKIL field of FIGCOM, at address 14(0)/705. This behavior helps
|
||||||
|
counteract lines which have been blocked by internet vulnerability
|
||||||
|
scanners injecting non-telnet data streams.
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.TP
|
.TP
|
||||||
@@ -166,13 +175,15 @@ Example:
|
|||||||
.EE
|
.EE
|
||||||
.TP
|
.TP
|
||||||
smlc.cfg
|
smlc.cfg
|
||||||
Used to associate sync serial (MDLC or HSSMLC) lines with a destination
|
Used to associate outbound sync serial (MDLC or HSSMLC) lines with destination
|
||||||
IP address and port number. Optional. Comments work the same as
|
IP addresses and port numbers, or to associate inbound sync serial lines
|
||||||
amlc.cfg. Example:
|
with port numbers. An outbound line corresponds to an RJE site defined as a
|
||||||
|
SLAVE site, and an inbound line corresponds to an RJE site defined as a MASTER
|
||||||
|
site. Optional. Comments work the same as amlc.cfg. Example:
|
||||||
|
|
||||||
.EX
|
.EX
|
||||||
0 10.1.1.3:2554
|
0 10.1.1.3:2554 # Connect to TCP port 2554 of host 10.1.1.3 for outbound line 0
|
||||||
1 127.0.0.1:2554
|
1 9951 # Listen on TCP port 9951 for inbound line 1
|
||||||
.EE
|
.EE
|
||||||
.TP
|
.TP
|
||||||
console.log
|
console.log
|
||||||
@@ -286,6 +297,7 @@ off|Start with tracing disabled
|
|||||||
all|Everything
|
all|Everything
|
||||||
flush|Flush trace file after each write
|
flush|Flush trace file after each write
|
||||||
tlb|STLB and IOTLB changes
|
tlb|STLB and IOTLB changes
|
||||||
|
smlc|MDLC/HSSMLC device I/O
|
||||||
OWNERL|Execution of this PCB
|
OWNERL|Execution of this PCB
|
||||||
#instruction count|Begin after specified number of instructions
|
#instruction count|Begin after specified number of instructions
|
||||||
|(the leading # is literal)
|
|(the leading # is literal)
|
||||||
|
|||||||
33
em.c
33
em.c
@@ -1,5 +1,5 @@
|
|||||||
/* Pr1me Computer emulator, Jim Wilcoxson (prirun@gmail.com), April 4, 2005
|
/* Pr1me Computer emulator, Jim Wilcoxson (prirun@gmail.com), April 4, 2005
|
||||||
Copyright (C) 2005-2019, Jim Wilcoxson. All Rights Reserved.
|
Copyright (C) 2005-2021, Jim Wilcoxson. All Rights Reserved.
|
||||||
|
|
||||||
Emulates a Prime Computer system by:
|
Emulates a Prime Computer system by:
|
||||||
- booting from a Prime disk image (normal usage)
|
- booting from a Prime disk image (normal usage)
|
||||||
@@ -287,6 +287,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
|
|||||||
T_PX Process exchange
|
T_PX Process exchange
|
||||||
T_LM License manager
|
T_LM License manager
|
||||||
T_TLB STLB and IOTLB changes
|
T_TLB STLB and IOTLB changes
|
||||||
|
T_SMLC SMLC device I/O
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define T_EAR 0x00000001
|
#define T_EAR 0x00000001
|
||||||
@@ -309,6 +310,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
|
|||||||
#define T_GET 0x00020000
|
#define T_GET 0x00020000
|
||||||
#define T_EAS 0x00040000
|
#define T_EAS 0x00040000
|
||||||
#define T_TLB 0x00080000
|
#define T_TLB 0x00080000
|
||||||
|
#define T_SMLC 0x00100000
|
||||||
|
|
||||||
#define BITMASK16(b) (0x8000 >> ((b)-1))
|
#define BITMASK16(b) (0x8000 >> ((b)-1))
|
||||||
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
|
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
|
||||||
@@ -656,6 +658,7 @@ static unsigned short *physmem = NULL; /* system's physical memory */
|
|||||||
|
|
||||||
//static ea_t tnoua_ea=0, tnou_ea=0, tsrc_ea=0;
|
//static ea_t tnoua_ea=0, tnou_ea=0, tsrc_ea=0;
|
||||||
static int domemdump; /* -memdump arg */
|
static int domemdump; /* -memdump arg */
|
||||||
|
static int dolinecleararg; /* -dolineclear arg */
|
||||||
|
|
||||||
static int tport; /* -tport option (incoming terminals) */
|
static int tport; /* -tport option (incoming terminals) */
|
||||||
static int nport; /* -nport option (PNC/Ringnet) */
|
static int nport; /* -nport option (PNC/Ringnet) */
|
||||||
@@ -4366,7 +4369,7 @@ int main (int argc, char **argv) {
|
|||||||
#define XRBRACE 0375
|
#define XRBRACE 0375
|
||||||
|
|
||||||
printf("[Prime Emulator ver %s %s]\n", REV, __DATE__);
|
printf("[Prime Emulator ver %s %s]\n", REV, __DATE__);
|
||||||
printf("[Copyright (C) 2005-2019 Jim Wilcoxson prirun@gmail.com]\n");
|
printf("[Copyright (C) 2005-2021 Jim Wilcoxson prirun@gmail.com]\n");
|
||||||
if (argc > 1 && (strcmp(argv[1],"--version") == 0)) {
|
if (argc > 1 && (strcmp(argv[1],"--version") == 0)) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
@@ -4449,6 +4452,7 @@ int main (int argc, char **argv) {
|
|||||||
#include "dispatch.h"
|
#include "dispatch.h"
|
||||||
|
|
||||||
domemdump = 0;
|
domemdump = 0;
|
||||||
|
dolinecleararg = 0;
|
||||||
bootarg = NULL;
|
bootarg = NULL;
|
||||||
bootfile[0] = 0;
|
bootfile[0] = 0;
|
||||||
gv.pmap32bits = 0;
|
gv.pmap32bits = 0;
|
||||||
@@ -4468,6 +4472,9 @@ int main (int argc, char **argv) {
|
|||||||
} else if (strcmp(argv[i],"-memdump") == 0) {
|
} else if (strcmp(argv[i],"-memdump") == 0) {
|
||||||
domemdump = 1;
|
domemdump = 1;
|
||||||
|
|
||||||
|
} else if (strcmp(argv[i],"-dolineclear") == 0) {
|
||||||
|
dolinecleararg = 1;
|
||||||
|
|
||||||
} else if (strcmp(argv[i],"-ss") == 0) {
|
} else if (strcmp(argv[i],"-ss") == 0) {
|
||||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||||
sscanf(argv[++i],"%o", &templ);
|
sscanf(argv[++i],"%o", &templ);
|
||||||
@@ -4606,6 +4613,8 @@ int main (int argc, char **argv) {
|
|||||||
setlinebuf(gv.tracefile);
|
setlinebuf(gv.tracefile);
|
||||||
else if (strcmp(argv[i],"tlb") == 0)
|
else if (strcmp(argv[i],"tlb") == 0)
|
||||||
gv.traceflags |= T_TLB;
|
gv.traceflags |= T_TLB;
|
||||||
|
else if (strcmp(argv[i],"smlc") == 0)
|
||||||
|
gv.traceflags |= T_SMLC;
|
||||||
else if (isdigit(argv[i][0]) && strlen(argv[i]) <= 3 && sscanf(argv[i],"%d", &templ) == 1)
|
else if (isdigit(argv[i][0]) && strlen(argv[i]) <= 3 && sscanf(argv[i],"%d", &templ) == 1)
|
||||||
gv.traceuser = 0100000 | (templ<<6); /* form OWNERL for user # */
|
gv.traceuser = 0100000 | (templ<<6); /* form OWNERL for user # */
|
||||||
else if (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1)
|
else if (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1)
|
||||||
@@ -6293,13 +6302,31 @@ d_hlt: /* 000000 */
|
|||||||
if (bootarg) {
|
if (bootarg) {
|
||||||
printf("\nCPU halt, instruction #%u at %o/%o %s: %o %o ^%06o^\nA='%o/%d B='%o/%d L='%o/%d X=%o/%d", gv.instcount, RPH, RPL, searchloadmap(gv.prevpc,' '), get16t(gv.prevpc), get16t(gv.prevpc+1), lights, getcrs16(A), getcrs16s(A), getcrs16(B), getcrs16s(B), getcrs32(A), getcrs32s(A), getcrs16(X), getcrs16s(X));
|
printf("\nCPU halt, instruction #%u at %o/%o %s: %o %o ^%06o^\nA='%o/%d B='%o/%d L='%o/%d X=%o/%d", gv.instcount, RPH, RPL, searchloadmap(gv.prevpc,' '), get16t(gv.prevpc), get16t(gv.prevpc+1), lights, getcrs16(A), getcrs16s(A), getcrs16(B), getcrs16s(B), getcrs32(A), getcrs32s(A), getcrs16(X), getcrs16s(X));
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int n;
|
||||||
|
static int ttydev;
|
||||||
|
ttydev = open("/dev/tty", O_RDWR, 0);
|
||||||
|
if (ttydev < 0) {
|
||||||
|
perror(" error opening /dev/tty");
|
||||||
|
fatal(NULL);
|
||||||
|
}
|
||||||
printf("\nPress Enter to continue, h to halt... ");
|
printf("\nPress Enter to continue, h to halt... ");
|
||||||
utempa = getchar();
|
fflush(stdout);
|
||||||
|
utempa = ' ';
|
||||||
|
n = 0;
|
||||||
|
while (n == 0)
|
||||||
|
n = read(ttydev, &utempa, 1);
|
||||||
|
/* utempa = getchar(); */
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (utempa == '\r' || utempa == '\n')
|
if (utempa == '\r' || utempa == '\n')
|
||||||
|
{
|
||||||
|
close(ttydev);
|
||||||
goto fetch;
|
goto fetch;
|
||||||
|
}
|
||||||
if (utempa == 'h')
|
if (utempa == 'h')
|
||||||
|
{
|
||||||
|
close(ttydev);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fatal("CPU halt");
|
fatal("CPU halt");
|
||||||
|
|||||||
Reference in New Issue
Block a user