mirror of
https://github.com/prirun/p50em.git
synced 2026-01-22 02:05:24 +00:00
Merge remote-tracking branch 'refs/remotes/origin/master'
This commit is contained in:
commit
25febc3947
@ -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
|
||||
repository.
|
||||
|
||||
Github discussions are now enabled for this repository, and can be
|
||||
used to ask for help.
|
||||
|
||||
## Public Systems
|
||||
|
||||
There are a set of emulators available for public use. These may be
|
||||
|
||||
504
devsmlc.h
504
devsmlc.h
@ -1,4 +1,3 @@
|
||||
#define DEBUG 0
|
||||
/*
|
||||
Implements the SMLC subsystem for Primos.
|
||||
|
||||
@ -48,8 +47,10 @@
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#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_NAK_STATUS (013<<4) /* encoded NAK 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 */
|
||||
|
||||
#define SMLC_CONNECTINTERVAL 15
|
||||
|
||||
#if DEBUG
|
||||
#define HexColumn(x) (3 * (x) + 4)
|
||||
#define AsciiColumn(x) (HexColumn(16) + 2 + (x))
|
||||
#define LogLineLength (AsciiColumn(16))
|
||||
@ -124,11 +125,9 @@
|
||||
static void smlclogbytes(unsigned char *bytes, int len);
|
||||
static void smlclogflush(void);
|
||||
|
||||
static FILE *smlclog = NULL;
|
||||
static char smlclogbuf[LogLineLength + 1];
|
||||
static int smlclogbytescol = 0;
|
||||
static char smlctimestamp[20];
|
||||
#endif
|
||||
|
||||
/* connection states */
|
||||
|
||||
@ -144,7 +143,9 @@ typedef enum {
|
||||
typedef enum {
|
||||
SMLC_STATERCVSYN = 0,
|
||||
SMLC_STATERCVDLE,
|
||||
SMLC_STATERCVCHAR
|
||||
SMLC_STATERCVCHAR,
|
||||
SMLC_STATERCVSOH,
|
||||
SMLC_STATERCVENQ
|
||||
} SmlcReceiveState;
|
||||
|
||||
/* controller interrupt states */
|
||||
@ -155,20 +156,18 @@ typedef enum {
|
||||
SMLC_INTERRUPTPENDING
|
||||
} SmlcInterruptState;
|
||||
|
||||
#if DEBUG
|
||||
static char *intstates[] = {
|
||||
"not interrupting",
|
||||
"interrupting",
|
||||
"interrupt pending"
|
||||
};
|
||||
#endif
|
||||
|
||||
/* send/receive buffer */
|
||||
|
||||
typedef struct smlcbuffer {
|
||||
unsigned short in;
|
||||
unsigned short out;
|
||||
char data[SMLC_BUFSIZE];
|
||||
unsigned char data[SMLC_BUFSIZE];
|
||||
} SmlcBuffer;
|
||||
|
||||
/* Simplex Line Control Block. */
|
||||
@ -195,7 +194,7 @@ typedef struct plcb { /* physical line control block */
|
||||
SmlcReceiveState recvstate; /* receive state */
|
||||
bool starting; /* TRUE if waiting for response to SOH-ENQ */
|
||||
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 */
|
||||
uint32_t host; /* TCP host */
|
||||
unsigned short port; /* TCP port */
|
||||
@ -225,19 +224,12 @@ static void smlcaddstatus(SmlcDCB *dcbp, int line, unsigned short status) {
|
||||
dmcbufbegea = dmcpair >> 16;
|
||||
dmcbufendea = dmcpair & 0xffff;
|
||||
if (dmcbufendea >= dmcbufbegea) {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Interrupt status '%06o added for line %d on device '%02o, next '%06o, last '%06o\n",
|
||||
TRACE(T_SMLC, "%s Interrupt status '%06o added for line %d on device '%02o, next '%06o, last '%06o\n",
|
||||
smlctimestamp, status, line, dcbp->deviceid, dmcbufbegea, dmcbufendea);
|
||||
#endif
|
||||
put16io(status + (line * 2), dmcbufbegea);
|
||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||
put16io(dmcbufbegea, dcbp->dmcstatus);
|
||||
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 struct timeval timeout = {0, 0};
|
||||
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen;
|
||||
char *bp;
|
||||
char buf[SMLC_BUFSIZE];
|
||||
int bufidx;
|
||||
@ -259,11 +253,12 @@ int devsmlc (int class, int func, int device) {
|
||||
short dmcnw;
|
||||
unsigned int dmcpair;
|
||||
int dx;
|
||||
char *ep;
|
||||
unsigned char *ep;
|
||||
int fd;
|
||||
int flags;
|
||||
uint32_t hostaddr;
|
||||
int i;
|
||||
char *ip;
|
||||
unsigned char *ip;
|
||||
PLCB *lp;
|
||||
bool isetb;
|
||||
int lx;
|
||||
@ -271,11 +266,10 @@ int devsmlc (int class, int func, int device) {
|
||||
int maxfd;
|
||||
int n;
|
||||
int nbytes;
|
||||
char *np;
|
||||
char *op;
|
||||
unsigned char *np;
|
||||
unsigned char *op;
|
||||
socklen_t optlen;
|
||||
int optval;
|
||||
struct sockaddr_in raddr;
|
||||
fd_set readfds;
|
||||
int readycount;
|
||||
int rc;
|
||||
@ -284,16 +278,14 @@ int devsmlc (int class, int func, int device) {
|
||||
int sx;
|
||||
unsigned short word;
|
||||
fd_set writefds;
|
||||
#if DEBUG
|
||||
struct tm *tp;
|
||||
struct timespec sts;
|
||||
#endif
|
||||
|
||||
currenttime = time(0);
|
||||
#if DEBUG
|
||||
#ifndef NOTRACE
|
||||
tp = localtime(¤ttime);
|
||||
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
|
||||
|
||||
switch (device) {
|
||||
@ -320,20 +312,13 @@ int devsmlc (int class, int func, int device) {
|
||||
|
||||
if (!inited) {
|
||||
FILE *cfgfile;
|
||||
char devname[32];
|
||||
int lc;
|
||||
int tempport;
|
||||
struct hostent* host;
|
||||
int lc;
|
||||
char *p;
|
||||
char tcpaddr[MAXHOSTLEN + 1];
|
||||
int tempport;
|
||||
|
||||
#if DEBUG
|
||||
smlclog = fopen("smlc.log", "wt");
|
||||
if (smlclog == NULL) {
|
||||
fprintf(stderr, "Failed to create smlclog.txt - aborting\n");
|
||||
fatal(NULL);
|
||||
}
|
||||
smlclogflush(); // initialize log buffer
|
||||
#endif
|
||||
smlclogflush(); // initialize log buffer for BSC frames
|
||||
|
||||
/* 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) {
|
||||
int n;
|
||||
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 */
|
||||
if (buf[0] == '\0' || buf[0] == ';' || buf[0] == '#')
|
||||
continue;
|
||||
n = sscanf(buf, "%d %s", &i, devname);
|
||||
n = sscanf(buf, "%d %s", &i, tcpaddr);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Line %d, SMLC line %d set to device %s\n", smlctimestamp, lc, i, devname);
|
||||
#endif
|
||||
dx = i / SMLC_LINESPERBOARD;
|
||||
lx = i % SMLC_LINESPERBOARD;
|
||||
if (strlen(devname) > MAXHOSTLEN) {
|
||||
fprintf(stderr, "Line %d of smlc.cfg ignored: IP address too long\n", lc);
|
||||
if (strlen(tcpaddr) > MAXHOSTLEN) {
|
||||
fprintf(stderr, "smlc.cfg[%d] IP address too long: %s\n", lc, buf);
|
||||
continue;
|
||||
}
|
||||
tempport = 0;
|
||||
if ((p=strtok(devname, PDELIM)) != NULL) {
|
||||
host = gethostbyname(p);
|
||||
host = NULL;
|
||||
p = index(tcpaddr, ':');
|
||||
if (p != NULL) {
|
||||
*p++ = '\0';
|
||||
host = gethostbyname(tcpaddr);
|
||||
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;
|
||||
}
|
||||
if ((p=strtok(NULL, DELIM)) != NULL) {
|
||||
tempport = atoi(p);
|
||||
if (tempport < 1 || tempport > 65000) {
|
||||
fprintf(stderr, "Line %d of smlc.cfg ignored: port number %d out of range 1-65000\n", tempport, lc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
tempport = atoi(p);
|
||||
} else {
|
||||
tempport = atoi(tcpaddr);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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,
|
||||
(hostaddr >> 8) & 0xff, hostaddr & 0xff, tempport);
|
||||
dc[dx].plines[lx].host = hostaddr;
|
||||
dc[dx].plines[lx].port = tempport;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s TCP address, host=%x, port=%d, controller=%d, line=%d\n", smlctimestamp, dc[dx].plines[lx].host,
|
||||
tempport, dx, lx);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s smlc.cfg[%d] controller '%02o, line %d, TCP address %s\n", smlctimestamp, lc, dx + 050, lx,
|
||||
dc[dx].plines[lx].remoteID);
|
||||
}
|
||||
fclose(cfgfile);
|
||||
}
|
||||
@ -445,40 +427,30 @@ int devsmlc (int class, int func, int device) {
|
||||
switch (func) {
|
||||
|
||||
case 000: // enable high-speed SMLC clock
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OCP '%02o%02o enable high-speed clock\n", smlctimestamp, func, device);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OCP '%02o%02o enable high-speed clock\n", smlctimestamp, func, device);
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
case 013: // acknowledge and clear interrupt
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OCP '%02o%02o acknowledge and clear interrupt\n", smlctimestamp, func, device);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OCP '%02o%02o acknowledge and clear interrupt\n", smlctimestamp, func, device);
|
||||
dc[dx].intstate = SMLC_NOTINTERRUPTING;
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
case 015: // enable interrupts
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OCP '%02o%02o enable interrupts\n", smlctimestamp, func, device);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OCP '%02o%02o enable interrupts\n", smlctimestamp, func, device);
|
||||
dc[dx].intenabled = 1;
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
case 016: // disable interrupts
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OCP '%02o%02o disable interrupts\n", smlctimestamp, func, device);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OCP '%02o%02o disable interrupts\n", smlctimestamp, func, device);
|
||||
dc[dx].intenabled = 0;
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
case 017: // initialize controller
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OCP '%02o%02o initialize controller\n", smlctimestamp, func, device);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OCP '%02o%02o initialize controller\n", smlctimestamp, func, device);
|
||||
dc[dx].intvector = 0;
|
||||
dc[dx].intenabled = 0;
|
||||
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);
|
||||
|
||||
if (func == 004) { /* skip if not interrupting */
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s SKS '02%02o skip if not interrupting, state is %s\n", smlctimestamp, device, intstates[dc[dx].intstate]);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s SKS '02%02o skip if not interrupting, state is %s\n", smlctimestamp, device, intstates[dc[dx].intstate]);
|
||||
if (dc[dx].intstate == SMLC_INTERRUPTING) {
|
||||
IOSKIP;
|
||||
}
|
||||
@ -564,16 +534,12 @@ int devsmlc (int class, int func, int device) {
|
||||
}
|
||||
}
|
||||
putcrs16(A, data);
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s INA '00%02o input status returns 0x%04x\n", smlctimestamp, device, data);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s INA '00%02o input status returns 0x%04x\n", smlctimestamp, device, data);
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 011) { /* report device ID */
|
||||
putcrs16(A, SMLC_DEVICEID);
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s INA '11%02o report device ID returns 0x%04x\n", smlctimestamp, device, getcrs16(A));
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s INA '11%02o report device ID returns 0x%04x\n", smlctimestamp, device, getcrs16(A));
|
||||
IOSKIP;
|
||||
|
||||
} else {
|
||||
@ -595,9 +561,7 @@ int devsmlc (int class, int func, int device) {
|
||||
data = getcrs16(A);
|
||||
dc[dx].fncode = data >> 8;
|
||||
dc[dx].lineno = data & 0377;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '00%02o set function/line '%03o/'%03o\n", smlctimestamp, device, dc[dx].fncode, dc[dx].lineno);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '00%02o set function/line '%03o/'%03o\n", smlctimestamp, device, dc[dx].fncode, dc[dx].lineno);
|
||||
switch (dc[dx].fncode) {
|
||||
|
||||
case 000: // set modem controls
|
||||
@ -627,15 +591,11 @@ int devsmlc (int class, int func, int device) {
|
||||
switch (dc[dx].fncode) {
|
||||
|
||||
case 000: // set modem controls
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set modem controls '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
fprintf(smlclog, "%s DTR: %d, RTS: %d\n", smlctimestamp, data & 1, (data & 2) == 1);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%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);
|
||||
sp->dtr = data & 1;
|
||||
if ((data & 1) == 0 && lp->fd != -1) {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s close connection to %s\n", smlctimestamp, lp->remoteID);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s close connection to %s\n", smlctimestamp, lp->remoteID);
|
||||
close(lp->fd);
|
||||
lp->fd = -1;
|
||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
||||
@ -647,9 +607,7 @@ int devsmlc (int class, int func, int device) {
|
||||
case 010: // set special character
|
||||
i = (data >> 8) & 0xff;
|
||||
ch = data & 0xff;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set special character %d <%02x>\n", smlctimestamp, device, dc[dx].lineno, i, ch);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set special character %d <%02x>\n", smlctimestamp, device, dc[dx].lineno, i, ch);
|
||||
if (i < SMLC_MAXSPCHARS) {
|
||||
sp->spchars[i] = ch;
|
||||
} else {
|
||||
@ -660,30 +618,26 @@ int devsmlc (int class, int func, int device) {
|
||||
break;
|
||||
|
||||
case 012: // set configuration word
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set configuration word 0x%04x\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set configuration word 0x%04x\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
sp->configword = data;
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
case 014: // set primary I/O channel
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set primary I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set primary I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
sp->dmcprimarycount = (data >> 12) + 1;
|
||||
sp->dmcprimaryidx = 0;
|
||||
sp->dmcprimary = data & 0x7fe;
|
||||
if (data != 0) {
|
||||
if ((data & 04000) == 0) fatal("Can't run SMLC in DMA mode!");
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s %d buffers\n", smlctimestamp, sp->dmcprimarycount);
|
||||
#ifndef NOTRACE
|
||||
TRACE(T_SMLC, "%s %d buffers\n", smlctimestamp, sp->dmcprimarycount);
|
||||
for (i = 0; i < sp->dmcprimarycount; i++) {
|
||||
dmcpair = get32io ((data & 0x7fe) + (i * 2));
|
||||
dmcbufbegea = dmcpair >> 16;
|
||||
dmcbufendea = dmcpair & 0xffff;
|
||||
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
|
||||
}
|
||||
@ -691,10 +645,8 @@ int devsmlc (int class, int func, int device) {
|
||||
break;
|
||||
|
||||
case 015: // enable
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o enable '%06o (%s %s)\n", smlctimestamp, device, dc[dx].lineno, data,
|
||||
TRACE(T_SMLC, "%s OTA '01%02o line '%02o enable '%06o (%s %s)\n", smlctimestamp, device, dc[dx].lineno, data,
|
||||
sx ? "xmit" : "recv", (data & 1) ? "on" : "off");
|
||||
#endif
|
||||
sp->enabled = data & 1;
|
||||
if (sp->enabled) devpoll[device] = 1;
|
||||
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
|
||||
* storing recceived data between the primary and backup channels.
|
||||
*/
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set backup I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set backup I/O channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
sp->dmcbackupcount = (data >> 12) + 1;
|
||||
sp->dmcbackupidx = 0;
|
||||
sp->dmcbackup = data & 0x7fe;
|
||||
if (data != 0) {
|
||||
if ((data & 04000) == 0) fatal("Can't run SMLC in DMA mode!");
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s %d buffers\n", smlctimestamp, sp->dmcbackupcount);
|
||||
#ifndef NOTRACE
|
||||
TRACE(T_SMLC, "%s %d buffers\n", smlctimestamp, sp->dmcbackupcount);
|
||||
for (i = 0; i < sp->dmcbackupcount; i++) {
|
||||
dmcpair = get32io ((data & 0x7fe) + (i * 2));
|
||||
dmcbufbegea = dmcpair >> 16;
|
||||
dmcbufendea = dmcpair & 0xffff;
|
||||
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
|
||||
}
|
||||
@ -729,9 +679,7 @@ int devsmlc (int class, int func, int device) {
|
||||
break;
|
||||
|
||||
case 017: // set status channel
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '01%02o line '%02o set status channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '01%02o line '%02o set status channel '%06o\n", smlctimestamp, device, dc[dx].lineno, data);
|
||||
if (!(data & 04000) && data != 0)
|
||||
fatal("Can't run SMLC in DMA mode!");
|
||||
if (lx != 0 || sx != 0) {
|
||||
@ -740,9 +688,7 @@ int devsmlc (int class, int func, int device) {
|
||||
fatal(NULL);
|
||||
}
|
||||
dc[dx].dmcstatus = data & 0x7fe;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s next %06o, last %06o\n", smlctimestamp, get32io(dc[dx].dmcstatus) >> 16, get32io(dc[dx].dmcstatus) & 0xffff);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s next %06o, last %06o\n", smlctimestamp, get32io(dc[dx].dmcstatus) >> 16, get32io(dc[dx].dmcstatus) & 0xffff);
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
@ -754,9 +700,7 @@ int devsmlc (int class, int func, int device) {
|
||||
break;
|
||||
|
||||
case 016: // set interrupt vector
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s OTA '16%02o set interrupt vector '%06o\n", smlctimestamp, device, getcrs16(A));
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s OTA '16%02o set interrupt vector '%06o\n", smlctimestamp, device, getcrs16(A));
|
||||
dc[dx].intvector = getcrs16(A);
|
||||
IOSKIP;
|
||||
break;
|
||||
@ -785,9 +729,7 @@ int devsmlc (int class, int func, int device) {
|
||||
} else {
|
||||
gv.intvec = dc[dx].intvector;
|
||||
dc[dx].intstate = SMLC_INTERRUPTING;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Raise interrupt on device '%02o\n", smlctimestamp, device);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s Raise interrupt on device '%02o\n", smlctimestamp, device);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -798,23 +740,41 @@ int devsmlc (int class, int func, int device) {
|
||||
|
||||
for (lx = 0; lx < SMLC_LINESPERBOARD; lx++) {
|
||||
lp = &dc[dx].plines[lx];
|
||||
if (lp->host == 0) continue;
|
||||
if (lp->port == 0) continue;
|
||||
switch (lp->connstate) {
|
||||
|
||||
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);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Failed to create socket for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||
fatal(NULL);
|
||||
}
|
||||
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optenable, sizeof(optenable));
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
bzero((char *) &raddr, sizeof(raddr));
|
||||
raddr.sin_family = AF_INET;
|
||||
raddr.sin_addr.s_addr = htonl(dc[dx].plines[lx].host);
|
||||
raddr.sin_port = htons(dc[dx].plines[lx].port);
|
||||
rc = connect(fd, (struct sockaddr *)&raddr, sizeof(raddr));
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optenable, sizeof(optenable)) == -1) {
|
||||
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);
|
||||
}
|
||||
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;
|
||||
if (rc < 0 && errno != EINPROGRESS) {
|
||||
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;
|
||||
break;
|
||||
} else { // connection in progress
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Connection initiated to %s for SMLC line %d\n", smlctimestamp, lp->remoteID,
|
||||
TRACE(T_SMLC, "%s Connection initiated to %s for SMLC line %d\n", smlctimestamp, lp->remoteID,
|
||||
(dx * SMLC_LINESPERBOARD) + lx);
|
||||
#endif
|
||||
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:
|
||||
FD_SET(lp->fd, &writefds);
|
||||
if (lp->fd > maxfd) maxfd = lp->fd;
|
||||
if (lp->host != 0) {
|
||||
//
|
||||
// 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;
|
||||
|
||||
case SMLC_STATECONNECTED:
|
||||
@ -863,11 +872,9 @@ int devsmlc (int class, int func, int device) {
|
||||
if (dmcnw <= 0) {
|
||||
sp->dmcprimaryidx += 1;
|
||||
} else {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Line %d on device '%02o send to %s from channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
||||
TRACE(T_SMLC, "%s Line %d on device '%02o send to %s from channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
||||
sp->dmcprimary);
|
||||
fprintf(smlclog, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
||||
n = 0;
|
||||
while (n < dmcnw && np + 1 < ep) {
|
||||
word = get16io(dmcbufbegea);
|
||||
@ -876,10 +883,8 @@ int devsmlc (int class, int func, int device) {
|
||||
*np++ = word & 0377;
|
||||
n += 1;
|
||||
}
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s %d words transferred to output buffer\n", smlctimestamp, n);
|
||||
fprintf(smlclog, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s %d words transferred to output buffer\n", smlctimestamp, n);
|
||||
TRACE(T_SMLC, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
||||
put16io(dmcbufbegea, sp->dmcprimary + (sp->dmcprimaryidx * 2));
|
||||
if (n == dmcnw) {
|
||||
status = SMLC_EOR | SMLC_XMIT;
|
||||
@ -925,7 +930,7 @@ int devsmlc (int class, int func, int device) {
|
||||
|
||||
for (lx = 0; lx < SMLC_LINESPERBOARD; lx++) {
|
||||
lp = &dc[dx].plines[lx];
|
||||
if (lp->host == 0) continue;
|
||||
if (lp->port == 0) continue;
|
||||
switch (lp->connstate) {
|
||||
|
||||
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);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Failed to get socket status for SMLC line %d\n", (dx * SMLC_LINESPERBOARD) + lx);
|
||||
close(lp->fd);
|
||||
lp->fd = -1;
|
||||
lp->nextconntime = currenttime + SMLC_CONNECTINTERVAL;
|
||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
||||
fatal(NULL);
|
||||
} 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);
|
||||
close(lp->fd);
|
||||
@ -945,47 +947,72 @@ int devsmlc (int class, int func, int device) {
|
||||
lp->nextconntime = currenttime + SMLC_CONNECTINTERVAL;
|
||||
lp->connstate = SMLC_STATEDISCONNECTED;
|
||||
} else {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Connection created to %s for SMLC line %d\n", smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s Connection created to %s for SMLC line %d\n", smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx);
|
||||
lp->connstate = SMLC_STATECONNECTED;
|
||||
lp->recvstate = SMLC_STATERCVSYN;
|
||||
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);
|
||||
}
|
||||
} else if (FD_ISSET(lp->fd, &readfds)) {
|
||||
addrlen = sizeof(addr);
|
||||
fd = accept(lp->fd, (struct sockaddr *)&addr, &addrlen);
|
||||
if (fd >= 0) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optenable, sizeof(optenable)) == -1) {
|
||||
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)
|
||||
break;
|
||||
if (lp->connstate == SMLC_STATECONNECTED) {
|
||||
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:
|
||||
sp = &lp->slines[SMLC_RECVIX];
|
||||
if (FD_ISSET(lp->fd, &readfds)) {
|
||||
n = read(lp->fd, &sp->buf.data[sp->buf.in], sizeof(sp->buf.data) - sp->buf.in);
|
||||
if (n > 0) {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Line %d on device '%02o received %d bytes from %s:\n", smlctimestamp, lx, device, n, lp->remoteID);
|
||||
#ifndef NOTRACE
|
||||
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);
|
||||
smlclogflush();
|
||||
#endif
|
||||
sp->buf.in += n;
|
||||
} else if (n < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)) {
|
||||
n = 0;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s recv from %s for line %d returned errno %d (ignored)\n",
|
||||
TRACE(T_SMLC, "%s read from %s for line %d returned errno %d (ignored)\n",
|
||||
smlctimestamp, lp->remoteID, (dx * SMLC_LINESPERBOARD) + lx, errno);
|
||||
#endif
|
||||
} else {
|
||||
#if DEBUG
|
||||
#ifndef NOTRACE
|
||||
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);
|
||||
} 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
|
||||
lp->connstate = SMLC_STATEDISCONNECTING;
|
||||
@ -1007,17 +1034,15 @@ int devsmlc (int class, int func, int device) {
|
||||
sp->dmcprimaryidx += 1;
|
||||
continue;
|
||||
}
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Line %d on device '%02o receive from %s to channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
||||
TRACE(T_SMLC, "%s Line %d on device '%02o receive from %s to channel '%06o\n", smlctimestamp, lx, device, lp->remoteID,
|
||||
sp->dmcprimary);
|
||||
fprintf(smlclog, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s next '%06o, last '%06o, words %d\n", smlctimestamp, dmcbufbegea, dmcbufendea, dmcnw);
|
||||
maxbytes = dmcnw * 2;
|
||||
n = 0;
|
||||
dmcnw = 0;
|
||||
status = 0;
|
||||
isetb = 0;
|
||||
while (n < maxbytes && np < ip) {
|
||||
while (n < maxbytes && np < ip && status == 0) {
|
||||
ch = *np++;
|
||||
if (lp->recvstate == SMLC_STATERCVSYN) {
|
||||
if (ch == SMLC_SYN) {
|
||||
@ -1030,10 +1055,8 @@ int devsmlc (int class, int func, int device) {
|
||||
lp->recvstate = SMLC_STATERCVSYN;
|
||||
break;
|
||||
} else {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s NAK received after sending NAK to %s for line %d\n", smlctimestamp, lp->remoteID,
|
||||
TRACE(T_SMLC, "%s NAK received after sending NAK to %s for line %d\n", smlctimestamp, lp->remoteID,
|
||||
(dx * SMLC_LINESPERBOARD) + lx);
|
||||
#endif
|
||||
lp->connstate = SMLC_STATEDISCONNECTING;
|
||||
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT);
|
||||
devpoll[device] = 1; /* return ASAP */
|
||||
@ -1052,29 +1075,64 @@ int devsmlc (int class, int func, int device) {
|
||||
word = ch << 8;
|
||||
}
|
||||
n += 1;
|
||||
if (lp->recvstate == SMLC_STATERCVDLE) {
|
||||
switch (lp->recvstate) {
|
||||
case SMLC_STATERCVDLE:
|
||||
lp->recvstate = SMLC_STATERCVCHAR;
|
||||
if (ch == SMLC_ACK0) {
|
||||
switch (ch) {
|
||||
case SMLC_ACK0:
|
||||
status |= SMLC_ENCODE_BIT | SMLC_ACK0_STATUS;
|
||||
lp->recvstate = SMLC_STATERCVSYN;
|
||||
break;
|
||||
} else if (ch == SMLC_STX) {
|
||||
case SMLC_STX:
|
||||
status |= SMLC_ENCODE_BIT | SMLC_STX_STATUS;
|
||||
break;
|
||||
} else if (ch == SMLC_ETB) {
|
||||
case SMLC_ETB:
|
||||
status |= SMLC_ENCODE_BIT | SMLC_ETB_STATUS;
|
||||
lp->recvstate = SMLC_STATERCVSYN;
|
||||
isetb = 1;
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
} else if (ch == SMLC_DLE) {
|
||||
lp->recvstate = SMLC_STATERCVDLE;
|
||||
break;
|
||||
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 < maxbytes
|
||||
&& ((n > 1 && *(np - 1) == SMLC_ETB && *(np - 2) == SMLC_DLE)
|
||||
|| (n == 1 && *(np - 1) == SMLC_NAK))) {
|
||||
&& (status & SMLC_ENCODE_BIT) != 0
|
||||
&& ( (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);
|
||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||
dmcnw += 1;
|
||||
@ -1085,10 +1143,8 @@ int devsmlc (int class, int func, int device) {
|
||||
}
|
||||
put16io(dmcbufbegea, sp->dmcprimary + (sp->dmcprimaryidx * 2));
|
||||
sp->dmcprimaryidx += 1;
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s %d words transferred from input buffer\n", smlctimestamp, dmcnw);
|
||||
fprintf(smlclog, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
||||
#endif
|
||||
TRACE(T_SMLC, "%s %d words transferred from input buffer\n", smlctimestamp, dmcnw);
|
||||
TRACE(T_SMLC, "%s next '%06o, last '%06o\n", smlctimestamp, dmcbufbegea, dmcbufendea);
|
||||
if (n == maxbytes) {
|
||||
status |= SMLC_EOR;
|
||||
} 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;
|
||||
n = write(lp->fd, &sp->buf.data[sp->buf.out], nbytes);
|
||||
if (n >= 0) {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Line %d on device '%02o sent %d bytes to %s:\n", smlctimestamp, lx, device, n, lp->remoteID);
|
||||
#ifndef NOTRACE
|
||||
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);
|
||||
smlclogflush();
|
||||
#endif
|
||||
@ -1128,10 +1184,8 @@ int devsmlc (int class, int func, int device) {
|
||||
smlcaddstatus(&dc[dx], lx, SMLC_LCT | SMLC_XMIT);
|
||||
}
|
||||
} else if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) {
|
||||
#if DEBUG
|
||||
fprintf(smlclog, "%s Connection failed to %s for line %d with errno %d\n", smlctimestamp, lp->remoteID,
|
||||
TRACE(T_SMLC, "%s Connection failed to %s for line %d with errno %d\n", smlctimestamp, lp->remoteID,
|
||||
(dx * SMLC_LINESPERBOARD) + lx, errno);
|
||||
#endif
|
||||
lp->connstate = SMLC_STATEDISCONNECTING;
|
||||
smlcaddstatus(&dc[dx], lx, SMLC_DSS_BIT);
|
||||
devpoll[device] = 1; /* return ASAP */
|
||||
@ -1155,7 +1209,6 @@ int devsmlc (int class, int func, int device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static unsigned char ebcdicToAscii[256] = {
|
||||
/* 00-07 */ 0x00, 0x01, 0x02, 0x03, 0x1a, 0x09, 0x1a, 0x7f,
|
||||
/* 08-0F */ 0x1a, 0x1a, 0x1a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
@ -1193,14 +1246,16 @@ static unsigned char ebcdicToAscii[256] = {
|
||||
};
|
||||
|
||||
static void smlclogflush(void) {
|
||||
#ifndef NOTRACE
|
||||
if (smlclogbytescol > 0) {
|
||||
fputs(smlclogbuf, smlclog);
|
||||
fputc('\n', smlclog);
|
||||
fflush(smlclog);
|
||||
fputs(smlclogbuf, gv.tracefile);
|
||||
fputc('\n', gv.tracefile);
|
||||
fflush(gv.tracefile);
|
||||
}
|
||||
smlclogbytescol = 0;
|
||||
memset(smlclogbuf, ' ', LogLineLength);
|
||||
smlclogbuf[LogLineLength] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
static void smlclogbytes(unsigned char *bytes, int len) {
|
||||
@ -1211,24 +1266,27 @@ static void smlclogbytes(unsigned char *bytes, int len) {
|
||||
int hexCol;
|
||||
int i;
|
||||
|
||||
ascCol = AsciiColumn(smlclogbytescol);
|
||||
hexCol = HexColumn(smlclogbytescol);
|
||||
#ifndef NOTRACE
|
||||
if (gv.traceflags & T_SMLC) {
|
||||
ascCol = AsciiColumn(smlclogbytescol);
|
||||
hexCol = HexColumn(smlclogbytescol);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
b = bytes[i];
|
||||
ac = ebcdicToAscii[b];
|
||||
if (ac < 0x20 || ac >= 0x7f) {
|
||||
ac = '.';
|
||||
}
|
||||
sprintf(hex, "%02x", b);
|
||||
memcpy(smlclogbuf + hexCol, hex, 2);
|
||||
hexCol += 3;
|
||||
smlclogbuf[ascCol++] = ac;
|
||||
if (++smlclogbytescol >= 16) {
|
||||
smlclogflush();
|
||||
ascCol = AsciiColumn(smlclogbytescol);
|
||||
hexCol = HexColumn(smlclogbytescol);
|
||||
for (i = 0; i < len; i++) {
|
||||
b = bytes[i];
|
||||
ac = ebcdicToAscii[b];
|
||||
if (ac < 0x20 || ac >= 0x7f) {
|
||||
ac = '.';
|
||||
}
|
||||
sprintf(hex, "%02x", b);
|
||||
memcpy(smlclogbuf + hexCol, hex, 2);
|
||||
hexCol += 3;
|
||||
smlclogbuf[ascCol++] = ac;
|
||||
if (++smlclogbytescol >= 16) {
|
||||
smlclogflush();
|
||||
ascCol = AsciiColumn(smlclogbytescol);
|
||||
hexCol = HexColumn(smlclogbytescol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
13
em.1
13
em.1
@ -166,13 +166,15 @@ Example:
|
||||
.EE
|
||||
.TP
|
||||
smlc.cfg
|
||||
Used to associate sync serial (MDLC or HSSMLC) lines with a destination
|
||||
IP address and port number. Optional. Comments work the same as
|
||||
amlc.cfg. Example:
|
||||
Used to associate outbound sync serial (MDLC or HSSMLC) lines with destination
|
||||
IP addresses and port numbers, or to associate inbound sync serial lines
|
||||
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
|
||||
0 10.1.1.3:2554
|
||||
1 127.0.0.1:2554
|
||||
0 10.1.1.3:2554 # Connect to TCP port 2554 of host 10.1.1.3 for outbound line 0
|
||||
1 9951 # Listen on TCP port 9951 for inbound line 1
|
||||
.EE
|
||||
.TP
|
||||
console.log
|
||||
@ -286,6 +288,7 @@ off|Start with tracing disabled
|
||||
all|Everything
|
||||
flush|Flush trace file after each write
|
||||
tlb|STLB and IOTLB changes
|
||||
smlc|MDLC/HSSMLC device I/O
|
||||
OWNERL|Execution of this PCB
|
||||
#instruction count|Begin after specified number of instructions
|
||||
|(the leading # is literal)
|
||||
|
||||
28
em.c
28
em.c
@ -1,5 +1,5 @@
|
||||
/* 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:
|
||||
- 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_LM License manager
|
||||
T_TLB STLB and IOTLB changes
|
||||
T_SMLC SMLC device I/O
|
||||
*/
|
||||
|
||||
#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_EAS 0x00040000
|
||||
#define T_TLB 0x00080000
|
||||
#define T_SMLC 0x00100000
|
||||
|
||||
#define BITMASK16(b) (0x8000 >> ((b)-1))
|
||||
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
|
||||
@ -4366,7 +4368,7 @@ int main (int argc, char **argv) {
|
||||
#define XRBRACE 0375
|
||||
|
||||
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)) {
|
||||
exit(0);
|
||||
}
|
||||
@ -4606,6 +4608,8 @@ int main (int argc, char **argv) {
|
||||
setlinebuf(gv.tracefile);
|
||||
else if (strcmp(argv[i],"tlb") == 0)
|
||||
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)
|
||||
gv.traceuser = 0100000 | (templ<<6); /* form OWNERL for user # */
|
||||
else if (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1)
|
||||
@ -6293,13 +6297,31 @@ d_hlt: /* 000000 */
|
||||
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));
|
||||
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... ");
|
||||
utempa = getchar();
|
||||
fflush(stdout);
|
||||
utempa = ' ';
|
||||
n = 0;
|
||||
while (n == 0)
|
||||
n = read(ttydev, &utempa, 1);
|
||||
/* utempa = getchar(); */
|
||||
printf("\n");
|
||||
if (utempa == '\r' || utempa == '\n')
|
||||
{
|
||||
close(ttydev);
|
||||
goto fetch;
|
||||
}
|
||||
if (utempa == 'h')
|
||||
{
|
||||
close(ttydev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fatal("CPU halt");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user