mirror of
https://github.com/prirun/p50em.git
synced 2026-03-06 02:38:57 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74aa7fe23e | ||
|
|
1819fed512 | ||
|
|
64c5970e97 | ||
|
|
c6c0344004 | ||
|
|
0466b4b603 | ||
|
|
256c72ca64 | ||
|
|
975cc951f8 | ||
|
|
29fbc31df6 | ||
|
|
f72b67b876 | ||
|
|
df6529c505 | ||
|
|
8782e6a63e | ||
|
|
88a43363e1 | ||
|
|
9fa1c77bad | ||
|
|
2d8397d1a4 | ||
|
|
244f2f49a2 | ||
|
|
af2b015383 | ||
|
|
902f535120 | ||
|
|
25febc3947 | ||
|
|
84afd8da7b | ||
|
|
d6d01cd05c | ||
|
|
ea2edd89de | ||
|
|
3d71fd85f0 | ||
|
|
5d119bb2c5 | ||
|
|
aa8095217f | ||
|
|
89043d09a4 |
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
# .editorconfig, Boone, 02/11/21
|
||||
# Editor behavior settings
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[makefile]
|
||||
indent_style = tab
|
||||
26
.github/workflows/freebsdbuild.yml
vendored
Normal file
26
.github/workflows/freebsdbuild.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: freebsdbuild
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: "vmactions/freebsd-vm@v0.1.3"
|
||||
with:
|
||||
usesh: true
|
||||
prepare: pkg install -y curl git
|
||||
run: |
|
||||
make
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "latest"
|
||||
prerelease: false
|
||||
title: "Bleeding Edge Binary - FreeBSD"
|
||||
files: |
|
||||
LICENSE
|
||||
README.md
|
||||
em.1
|
||||
em
|
||||
22
.github/workflows/linuxbuild.yml
vendored
Normal file
22
.github/workflows/linuxbuild.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: linuxbuild
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- name: make
|
||||
run: make
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "latest"
|
||||
prerelease: false
|
||||
title: "Bleeding Edge Binary - Ubuntu"
|
||||
files: |
|
||||
LICENSE
|
||||
README.md
|
||||
em.1
|
||||
em
|
||||
22
.github/workflows/macbuild.yml
vendored
Normal file
22
.github/workflows/macbuild.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: macbuild
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- name: make
|
||||
run: make
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "latest"
|
||||
prerelease: false
|
||||
title: "Bleeding Edge Binary - MacOS"
|
||||
files: |
|
||||
LICENSE
|
||||
README.md
|
||||
em.1
|
||||
em
|
||||
@@ -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
|
||||
@@ -52,7 +55,7 @@ business unit ceased to exist. A reformatted copy is available
|
||||
A growing collection of Prime and related documentation is available
|
||||
at [sysovl.info](https://sysovl.info/reference_prime.html).
|
||||
A howto on installing PRIMOS in the emulator is
|
||||
[here](https://sysovl.info/reference_prime_drb_installing_primos.html).
|
||||
[here](https://sysovl.info/reference_prime_drb_installoview.html).
|
||||
Discussion of adapting these instructions to
|
||||
22.1.4 has been occurring on the [cctalk mailing
|
||||
list](http://classiccmp.org/pipermail/cctalk/2020-March/052126.html).
|
||||
|
||||
90
devamlc.h
90
devamlc.h
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
Implements the AMLC subsystem for Primos. In earlier versions
|
||||
(r186), a more hardware-centric implementation was used that closely
|
||||
followed the design of Prime's real AMLC board. For example, every
|
||||
@@ -52,9 +52,9 @@
|
||||
NOTE: varying the AMLC poll rates dynamically is the default, but
|
||||
this can lead to unpredictable performance. If consistent,
|
||||
predictable performance is more important than absolute
|
||||
performance, MAXAMLCSPEEDUP can be set to 1. Then this
|
||||
performance, MAXAMLCSPEEDUP can be set to 1. Then this
|
||||
implementation will function more or less like a real Prime.
|
||||
|
||||
|
||||
|
||||
AMLC I/O operations:
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
AMLC status word (from AMLCT5):
|
||||
|
||||
BITS DESCRIPTION
|
||||
|
||||
|
||||
1 END OF RANGE INTERRUPT
|
||||
2 CLOCK RUNNING
|
||||
3-6 LINE # OF LINE WHOSE DATA SET STATUS HAS CHANGED
|
||||
@@ -150,6 +150,8 @@ AMLC status word (from AMLCT5):
|
||||
|
||||
*/
|
||||
|
||||
#include <termio.h>
|
||||
|
||||
/* this macro closes an AMLC connection - used in several places
|
||||
|
||||
NOTE: don't print disconnect message on dedicated lines */
|
||||
@@ -202,11 +204,11 @@ int devamlc (int class, int func, int device) {
|
||||
#define DSSCOUNTDOWN 25
|
||||
|
||||
/* connection types for each line. This _doesn't_ imply the line is
|
||||
actually connected, ie, an AMLC line may be tied to a specific
|
||||
actually connected, ie, an AMLC line may be tied to a specific
|
||||
serial device (like a USB->serial gizmo), but the USB device may
|
||||
not be plugged in. The connection type would be CT_SERIAL but
|
||||
the line's fd would be -1 and the "connected" bit would be 0 */
|
||||
|
||||
|
||||
#define CT_SOCKET 1
|
||||
#define CT_SERIAL 2
|
||||
#define CT_DEDIP 3
|
||||
@@ -262,6 +264,7 @@ int devamlc (int class, int func, int device) {
|
||||
unsigned short ctinterrupt; /* 1 bit per line */
|
||||
unsigned short dss; /* 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 dsstime; /* countdown to dss poll */
|
||||
short fd[16]; /* Unix fd, 1 per line */
|
||||
@@ -323,12 +326,13 @@ int devamlc (int class, int func, int device) {
|
||||
int tempport;
|
||||
struct hostent* host;
|
||||
char *p;
|
||||
|
||||
|
||||
/* initially, we don't know about any AMLC boards */
|
||||
|
||||
for (dx=0; dx<MAXBOARDS; dx++) {
|
||||
dc[dx].deviceid = 0;
|
||||
dc[dx].connected = 0;
|
||||
dc[dx].dolineclear = 0;
|
||||
dc[dx].serial = 0;
|
||||
for (lx = 0; lx < 16; lx++) {
|
||||
dc[dx].fd[lx] = -1;
|
||||
@@ -344,7 +348,7 @@ int devamlc (int class, int func, int device) {
|
||||
/* read the amlc.cfg file. This file has 3 uses:
|
||||
|
||||
1. maps Prime async lines to real serial devices, like host
|
||||
serial ports or USB serial boxes.
|
||||
serial ports or USB serial boxes.
|
||||
|
||||
Format: <line #> /dev/<Unix usb device name>
|
||||
|
||||
@@ -416,7 +420,7 @@ int devamlc (int class, int func, int device) {
|
||||
fprintf(stderr,"Line %d of amlc.cfg ignored: IP address too long\n", lc);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* break out host and port number; no port means this is
|
||||
an incoming dedicated line: no connects out. With a
|
||||
port means we need to connect to it. */
|
||||
@@ -551,13 +555,13 @@ int devamlc (int class, int func, int device) {
|
||||
/* XXX: this constant is redefined because of a bug in the
|
||||
OSX Prolific USB serial driver at version 1.2.1r2. They should be
|
||||
turning on bit 0100, but are turning on 0x0100. */
|
||||
#define TIOCM_CD 0x0100
|
||||
#define TIOCM_CD 0x0100
|
||||
|
||||
if (func == 00) { /* input Data Set Sense (carrier) */
|
||||
if (dc[dx].serial) { /* any serial connections? */
|
||||
if (--dc[dx].dsstime == 0) {
|
||||
dc[dx].dsstime = DSSCOUNTDOWN;
|
||||
#ifdef __APPLE__
|
||||
/* #ifdef __APPLE__ */
|
||||
for (lx = 0; lx < 16; lx++) { /* yes, poll them */
|
||||
if (dc[dx].ctype[lx] == CT_SERIAL) {
|
||||
int modemstate;
|
||||
@@ -573,7 +577,7 @@ int devamlc (int class, int func, int device) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
//printf("devamlc: dss for device '%o = 0x%x\n", device, dc[dx].dss);
|
||||
@@ -632,10 +636,10 @@ int devamlc (int class, int func, int device) {
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case CT_SERIAL: {
|
||||
int fd;
|
||||
|
||||
|
||||
/* setup line characteristics if they have changed (check for
|
||||
something other than DTR changing) */
|
||||
|
||||
@@ -705,7 +709,7 @@ int devamlc (int class, int func, int device) {
|
||||
1_0 - cts/rts flow control (2413 becomes 6413)
|
||||
1_1 - dsr/dtr flow control (2413 becomes 7413)
|
||||
|
||||
NOTE: bit 11 also appears to be free, but Primos doesn't
|
||||
NOTE: bit 11 also appears to be free, but Primos doesn't
|
||||
let it flow through to the AMLC controller. :(
|
||||
*/
|
||||
|
||||
@@ -756,7 +760,6 @@ int devamlc (int class, int func, int device) {
|
||||
|
||||
/* set DTR high (02000) or low if it has changed */
|
||||
|
||||
#ifdef __APPLE__
|
||||
if ((getcrs16(A) ^ dc[dx].lconf[lx]) & 02000) {
|
||||
int modemstate;
|
||||
//printf("devamlc: DTR state changed\n");
|
||||
@@ -769,7 +772,6 @@ int devamlc (int class, int func, int device) {
|
||||
}
|
||||
ioctl(fd, TIOCMSET, &modemstate);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -839,7 +841,7 @@ int devamlc (int class, int func, int device) {
|
||||
double ts;
|
||||
int neweor, activelines;
|
||||
//printf("poll device '%o, speedup=%5.2f, cti=%x, xmit=%x, recv=%x, dss=%x\n", device, pollspeedup, dc[dx].ctinterrupt, dc[dx].xmitenabled, dc[dx].recvenabled, dc[dx].dss);
|
||||
|
||||
|
||||
/* check for 1 new telnet connection every AMLCACCEPTSECS seconds
|
||||
(10 times per second) */
|
||||
|
||||
@@ -885,6 +887,7 @@ int devamlc (int class, int func, int device) {
|
||||
close(dc[i].fd[lx]);
|
||||
dc[i].dss |= BITMASK16(lx+1);
|
||||
dc[i].connected |= BITMASK16(lx+1);
|
||||
dc[i].dolineclear |= BITMASK16(lx+1);
|
||||
dc[i].fd[lx] = fd;
|
||||
dc[i].tstate[lx] = TS_DATA;
|
||||
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
|
||||
@@ -1033,7 +1036,7 @@ int devamlc (int class, int func, int device) {
|
||||
|
||||
int fd, sockflags;
|
||||
struct sockaddr_in raddr;
|
||||
|
||||
|
||||
dc[dx].obtimer[lx] = tv.tv_sec + AMLCCONNECT;
|
||||
//printf("em: trying to connect to 0x%08x:%d\n", dc[dx].obhost[lx], dc[dx].obport[lx]); /***/
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
@@ -1118,7 +1121,7 @@ int devamlc (int class, int func, int device) {
|
||||
}
|
||||
|
||||
/* process input, but only as much as will fit into the DMC
|
||||
buffer.
|
||||
buffer.
|
||||
|
||||
Because the size of the AMLC tumble tables is limited, this
|
||||
could pose a denial of service issue. Input is processed in a
|
||||
@@ -1140,6 +1143,53 @@ dorecv:
|
||||
if (dc[dx].deviceid == 0 || dc[dx].connected == 0 || dc[dx].eor)
|
||||
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 */
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
.I off
|
||||
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
|
||||
.TP
|
||||
@@ -166,13 +175,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 +297,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)
|
||||
|
||||
237
em.c
237
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)
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
$ time ./em -tport 8000 -cpuid 5 -boot 14714 -map MFD.2462/PRIRUN/RING0.MAP MFD.2462/PRIRUN/RING3.MAP 2>err
|
||||
|
||||
Disk boot device is 14uc4, tape is 10005,
|
||||
Disk boot device is 14uc4, tape is 10005,
|
||||
where u=1/3/5/7 for units 0/1/2/3
|
||||
and c=1/3/5/7 for controller 26/27/...
|
||||
(See complete boot table below)
|
||||
@@ -23,7 +23,7 @@
|
||||
NOTE: the -map command is optional, but is needed to set the
|
||||
real-time clock automatically for older models (cpuid < 15). If
|
||||
maps are not available, use the Primos SE command to set the clock
|
||||
manually after the system boots:
|
||||
manually after the system boots:
|
||||
SE -MMDDYY HHMM
|
||||
|
||||
-------------
|
||||
@@ -40,11 +40,11 @@ $ time ./em -cpuid 5 -boot SAM.SAVE 14114 2>err
|
||||
|
||||
Enter physical device = 2466
|
||||
|
||||
QUICK VERIFY MODE Enabled; Enter 'RESET QVFY' for normal operation.
|
||||
Enter 'SET DCM' to display CASE messages.
|
||||
QUICK VERIFY MODE Enabled; Enter 'RESET QVFY' for normal operation.
|
||||
Enter 'SET DCM' to display CASE messages.
|
||||
Enter 'LOAD;RUN' for Default Execution
|
||||
|
||||
SAM>
|
||||
SAM>
|
||||
|
||||
--------------
|
||||
Usage: to load initial boot from tape, then prompt for disk pdev
|
||||
@@ -56,7 +56,7 @@ Sense switches set to 1005 <--- these cause pdev prompt
|
||||
|
||||
PHYSICAL DEVICE=2466
|
||||
|
||||
DISK ERROR, STATUS: 000001
|
||||
DISK ERROR, STATUS: 000001
|
||||
PHYSICAL DEVICE=
|
||||
|
||||
---------------
|
||||
@@ -70,12 +70,12 @@ RUN FILE TREENAME=MFD>DOS>DOS.SAVE
|
||||
BOOTING FROM MT0 MFD>DOS>DOS.SAVE
|
||||
|
||||
|
||||
PRIMOS II REV 20.0 03/15/85 (AT 170000)
|
||||
PRIMOS II REV 20.0 03/15/85 (AT 170000)
|
||||
Copyright (c) Prime Computer, Inc. 1985.
|
||||
PRIMOS II is being phased out. To boot PRIMOS return to CP mode.
|
||||
PRIMOS II is being phased out. To boot PRIMOS return to CP mode.
|
||||
("BOOT 14xxx" will autoboot PRIMOS.)
|
||||
|
||||
OK:
|
||||
OK:
|
||||
---------------
|
||||
|
||||
TRACING:
|
||||
@@ -138,7 +138,7 @@ gv.tracetriggered = 1; this simulates the Ctrl-t.
|
||||
|
||||
Locations '40-'57 are reserved for 8 DMC channels, 2 words each.
|
||||
Locations '60-'77 are interrupt vectors
|
||||
Locations '100-'177 are for external device interrupts
|
||||
Locations '100-'177 are for external device interrupts
|
||||
see p. A-8 of Sys Arch
|
||||
|
||||
In VI mode, locations 0-'17 are trapped and map to the live
|
||||
@@ -191,7 +191,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
|
||||
|
||||
/* set condition codes based on V-mode FP accumulator
|
||||
|
||||
NOTES:
|
||||
NOTES:
|
||||
|
||||
-Prime considers anything with a zero fraction to be zero,
|
||||
even if the exponent is non-zero (this is a "dirty zero")
|
||||
@@ -202,7 +202,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
|
||||
|
||||
XXX: #define SETCC_F SETCC_32(getcrs32(FLTH))
|
||||
*/
|
||||
|
||||
|
||||
#define SETCC_F \
|
||||
CLEARCC; \
|
||||
if (getcrs32s(FLTH) < 0) \
|
||||
@@ -274,6 +274,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
|
||||
T_EAV trace V-mode effective address calculation
|
||||
T_EAI trace I-mode effective address calculation
|
||||
T_FLOW instruction summary
|
||||
T_FP floating point
|
||||
T_INST detailed instruction trace
|
||||
T_MODE trace CPU mode changes
|
||||
T_EAAP AP effective address calculation
|
||||
@@ -287,6 +288,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 +311,8 @@ 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 T_FP 0x00200000
|
||||
|
||||
#define BITMASK16(b) (0x8000 >> ((b)-1))
|
||||
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
|
||||
@@ -433,7 +437,7 @@ typedef struct {
|
||||
|
||||
The special cache can also be used for write references. Bits 2-4
|
||||
of the cache entry vpn are the access bits from mapva, so bit 4
|
||||
being 1 means that writes are allowed.
|
||||
being 1 means that writes are allowed.
|
||||
|
||||
IMPORTANT NOTE: bit 4 MUST BE CHECKED before all write references!
|
||||
*/
|
||||
@@ -655,7 +659,9 @@ static unsigned short *physmem = NULL; /* system's physical memory */
|
||||
#define LASTFAULT 077
|
||||
|
||||
//static ea_t tnoua_ea=0, tnou_ea=0, tsrc_ea=0;
|
||||
static int noclock; /* -noclock arg */
|
||||
static int domemdump; /* -memdump arg */
|
||||
static int dolinecleararg; /* -dolineclear arg */
|
||||
|
||||
static int tport; /* -tport option (incoming terminals) */
|
||||
static int nport; /* -nport option (PNC/Ringnet) */
|
||||
@@ -711,7 +717,7 @@ char *brp_name() {
|
||||
match; if the address isn't found exactly, the index returned
|
||||
will be the address lower than the requested address, or -1
|
||||
if the symbol table is empty or the requested address is
|
||||
lower than any in the symbol table
|
||||
lower than any in the symbol table
|
||||
|
||||
Symbol types:
|
||||
e = address of ecb
|
||||
@@ -848,7 +854,7 @@ char *searchloadmap(int addr, char type) {
|
||||
return buf[bufix];
|
||||
} else
|
||||
return mapsym[ix].symname;
|
||||
} else
|
||||
} else
|
||||
return ␣
|
||||
}
|
||||
|
||||
@@ -1067,11 +1073,11 @@ static unsigned int mapio(ea_t ea) {
|
||||
#define put64(value, ea) (put64r((value),(ea),RP))
|
||||
#define put64r0(value, ea) (put64r((value),(ea),0))
|
||||
|
||||
/*
|
||||
/*
|
||||
get16 handles 16-bit fetches that CANNOT cause address traps.
|
||||
|
||||
get16t handles 16-bit fetches that MIGHT cause address traps,
|
||||
indicated by the sign bit set in EA.
|
||||
indicated by the sign bit set in EA.
|
||||
Address traps can occur:
|
||||
- fetching S/R mode instructions
|
||||
- fetching V-mode instructions when RPL < 010 or 040 (seg enabled/not)
|
||||
@@ -1087,7 +1093,7 @@ static unsigned int mapio(ea_t ea) {
|
||||
get16r handles 16-bit fetches that used a passed-in virtual address;
|
||||
(only the ring part is used from this address).
|
||||
|
||||
VERY IMPORTANT: get16r _cannot_ use the supercache! You don't want to
|
||||
VERY IMPORTANT: get16r _cannot_ use the supercache! You don't want to
|
||||
cache Ring 0 accesses to data, then let Ring 3 use the cache! It could
|
||||
be changed to use a special R0 brp cache entry, but probably not much
|
||||
gain performance-wise. Might speed up process exchange...
|
||||
@@ -1487,7 +1493,7 @@ static void put64r(long long value, ea_t ea, ea_t rpring) {
|
||||
disk buffers and shutdown gracefully.
|
||||
|
||||
NOTE: it may take up to 1 minute for Primos to see the sensor
|
||||
check. User 1 will usually be at the OK, prompt, waiting on
|
||||
check. User 1 will usually be at the OK, prompt, waiting on
|
||||
input, and the check will occur when the 1-minute abort occurs.
|
||||
|
||||
NOTE: these are inactive if the emulator is using dedicated
|
||||
@@ -1542,7 +1548,7 @@ void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int dswsta
|
||||
}
|
||||
|
||||
|
||||
/* queue instructions
|
||||
/* queue instructions
|
||||
|
||||
NOTE: ABQ is typically used in software to add an item to a
|
||||
hardware (physical) queue and RTQ is used by DMQ hardware to fetch
|
||||
@@ -1550,7 +1556,7 @@ void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int dswsta
|
||||
support physical queues, but only ABQ and RTQ currently support
|
||||
them (they're needed for AMLC boards). If ICS support is added,
|
||||
the other queue instructions will probably need to support physical
|
||||
queues.
|
||||
queues.
|
||||
|
||||
The CPU KEYS are not set here because this would not happen on a
|
||||
DMQ request - only when the instruction is executed by software.
|
||||
@@ -1736,7 +1742,7 @@ static int (*devmap[64])(int, int, int) = {
|
||||
static void warn(char *msg) {
|
||||
printf("emulator warning:\n instruction #%u at %o/%o: %o %o keys=%o, modals=%o\n %s\n", gv.instcount, gv.prevpc >> 16, gv.prevpc & 0xFFFF, get16t(gv.prevpc), get16t(gv.prevpc+1),getcrs16(KEYS), getcrs16(MODALS), msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* return a string for the keys
|
||||
C = C bit set
|
||||
@@ -1789,7 +1795,7 @@ char *keystring(unsigned short keys) {
|
||||
/* return a string for the modals
|
||||
I = interrupts inhibited, bit 1 = 0
|
||||
E = interrupts enabled, bit 1 = 1
|
||||
|
||||
|
||||
V = vectored interrupt mode, bit 2 = 1
|
||||
|
||||
0-7 = CRS, bits 9-11
|
||||
@@ -1854,7 +1860,7 @@ static void fatal(char *msg) {
|
||||
if (msg)
|
||||
printf(": %s", msg);
|
||||
printf("\n");
|
||||
|
||||
|
||||
if (physmem != NULL) {
|
||||
printf("instruction #%u at %o/%o %s ^%06o^\nA='%o/%d B='%o/%d L='%o/%d X='%o/%d K=%o [%s]\nowner=%o %s, modals=%o [%s]\n", gv.instcount, gv.prevpc >> 16, gv.prevpc & 0xFFFF, searchloadmap(gv.prevpc,' '), lights, getcrs16(A), getcrs16s(A), getcrs16(B), getcrs16s(B), getcrs32(A), getcrs32s(A), getcrs16(X), getcrs16s(X), getcrs16(KEYS), keystring(getcrs16(KEYS)), getcrs16(OWNERL), searchloadmap(getcrs32(OWNER),' '), getcrs16(MODALS), modstring(getcrs16(MODALS)));
|
||||
|
||||
@@ -1896,7 +1902,7 @@ static void fatal(char *msg) {
|
||||
for (i=0; i<64; i++)
|
||||
devmap[i](-2, 0, i);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NOTRACE
|
||||
fclose(gv.tracefile);
|
||||
#endif
|
||||
@@ -1945,7 +1951,7 @@ static void newkeys (unsigned short new) {
|
||||
}
|
||||
|
||||
static void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
static unsigned char faultname[LASTFAULT-FIRSTFAULT+2][4] =
|
||||
static unsigned char faultname[LASTFAULT-FIRSTFAULT+2][4] =
|
||||
{"RXM", "PRC", "PAG", "SVC", "UII", "SEM", "MCK", "MM", "ILL", "ACC", "ARI", "STK", "SEG", "PTR", "-?-"};
|
||||
unsigned char *faultnamep;
|
||||
ea_t pcbp, pxfvec, csea, ea;
|
||||
@@ -1978,7 +1984,7 @@ static void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
regs.sym.pswkeys = crs[KEYS]; /* Prime->Prime: no swap! */
|
||||
putcrs16(FCODE, fcode);
|
||||
putcrs32(FADDR, faddr);
|
||||
|
||||
|
||||
if (FIRSTFAULT <= fvec && fvec <= LASTFAULT)
|
||||
faultnamep = faultname[fvec-FIRSTFAULT];
|
||||
else
|
||||
@@ -2070,7 +2076,7 @@ static void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
}
|
||||
|
||||
|
||||
/* 16S Addressing Mode
|
||||
/* 16S Addressing Mode
|
||||
|
||||
NOTE: when fetching indirect words via address traps, ie, the word
|
||||
is in a register, the segment and ring bits are unimportant. But
|
||||
@@ -2082,7 +2088,7 @@ static void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
*/
|
||||
|
||||
static ea_t ea16s (unsigned short inst) {
|
||||
|
||||
|
||||
unsigned short rpl, amask, i, x;
|
||||
int indlevel;
|
||||
ea_t ea, va;
|
||||
@@ -2121,7 +2127,7 @@ static ea_t ea16s (unsigned short inst) {
|
||||
/* 32S Addressing Mode */
|
||||
|
||||
static ea_t ea32s (unsigned short inst) {
|
||||
|
||||
|
||||
unsigned short rpl, amask, i, x;
|
||||
int indlevel;
|
||||
ea_t ea, va;
|
||||
@@ -2188,7 +2194,7 @@ static inline ea_t ea32r64r (ea_t earp, unsigned short inst) {
|
||||
TRACE(T_EAR, " PC relative, P=%o, new ea=%o\n", rpl, ea);
|
||||
eap = &gv.brp[RPBR];
|
||||
}
|
||||
else
|
||||
else
|
||||
goto special; /* special cases */
|
||||
else {
|
||||
eap = &gv.brp[S0BR];
|
||||
@@ -2349,7 +2355,7 @@ special:
|
||||
static ea_t apea(unsigned short *bitarg) {
|
||||
unsigned short ibr, ea_s, ea_w, bit, br, a;
|
||||
unsigned int utempl;
|
||||
ea_t ea, ip;
|
||||
ea_t ea, ip, iwea;
|
||||
|
||||
eap = &gv.brp[RPBR];
|
||||
utempl = get32(RP);
|
||||
@@ -2375,8 +2381,11 @@ static ea_t apea(unsigned short *bitarg) {
|
||||
bit = get16(INCVA(ea,2)) >> 12;
|
||||
else
|
||||
bit = 0;
|
||||
iwea = ea;
|
||||
ea = ip;
|
||||
TRACE(T_EAAP, " After indirect, AP ea = %o/%o, bit=%d %s\n", ea>>16, ea & 0xFFFF, bit, searchloadmap(ea,' '));
|
||||
if (ea & 0x80000000)
|
||||
fault(POINTERFAULT, ea>>16, iwea);
|
||||
}
|
||||
if (bitarg != NULL)
|
||||
*bitarg = bit;
|
||||
@@ -2416,7 +2425,7 @@ static inline void mathexception(unsigned char extype, unsigned short fcode, ea_
|
||||
putcrs16(KEYS, getcrs16(KEYS) | 0x8000);
|
||||
switch (extype) {
|
||||
case 'i':
|
||||
if (getcrs16(KEYS) & 0400)
|
||||
if (getcrs16(KEYS) & 0400)
|
||||
fault(ARITHFAULT, fcode, faddr);
|
||||
break;
|
||||
case 'd':
|
||||
@@ -2710,7 +2719,7 @@ static void argt() {
|
||||
rp = get32(stackfp+2);
|
||||
|
||||
/* reload the caller's base registers for EA calculations */
|
||||
|
||||
|
||||
brsave[0] = rp >> 16; brsave[1] = 0;
|
||||
/* set ring bits on LB and SB to get correct ring on args */
|
||||
brsave[2] = get16(stackfp+4) | ((rp >> 16) & RINGMASK16);
|
||||
@@ -2837,7 +2846,7 @@ static void pcl (ea_t ecbea) {
|
||||
/* get a copy of the ecb. gates must be aligned on a 16-word
|
||||
boundary, therefore can't cross a page boundary, and mapva has
|
||||
already ensured that the ecb page is resident. For a non-gate
|
||||
ecb, check to see if it crosses a page boundary. If not, a
|
||||
ecb, check to see if it crosses a page boundary. If not, a
|
||||
memcpy is okay; if it does, do fetches */
|
||||
|
||||
if (access == 1 && (ecbea & 0xF) != 0)
|
||||
@@ -2958,7 +2967,7 @@ static void pcl (ea_t ecbea) {
|
||||
Y(low) = number of arguments left to transfer (JW hack!) */
|
||||
|
||||
|
||||
/* if a page fault occurs during argument transfer, we need to
|
||||
/* if a page fault occurs during argument transfer, we need to
|
||||
make sure to use the current RP, which points to the ARGT
|
||||
instruction. Otherwise, the return from the page fault
|
||||
is to the PCL instruction, which has already completed at
|
||||
@@ -3040,7 +3049,7 @@ static void pcl (ea_t ecbea) {
|
||||
utempa = get16(get32(ea)); /* 1st arg: key */
|
||||
TRACEA(" TSRC$$: key = %d\n", utempa);
|
||||
eatemp = get32(ea+9); /* 4th arg: CP(1..2) */
|
||||
utempl = get32(eatemp);
|
||||
utempl = get32(eatemp);
|
||||
utempa1 = utempl>>16; /* starting cp */
|
||||
utempa2 = utempl&0xffff; /* # chars */
|
||||
TRACEA(" cp(0)=%d, cp(1)=%d, loc(cp)=%o/%o\n", utempa1, utempa2, eatemp>>16, eatemp&0xffff);
|
||||
@@ -3118,7 +3127,7 @@ static void calf(ea_t ea) {
|
||||
for (i=0; i<6; i++)
|
||||
cs[i] = get16r0(csea+i);
|
||||
|
||||
/* pop the concealed stack
|
||||
/* pop the concealed stack
|
||||
XXX: this was after code below. Does it matter? */
|
||||
|
||||
put16r0(this, pcbp+PCBCSNEXT);
|
||||
@@ -3138,7 +3147,7 @@ static void calf(ea_t ea) {
|
||||
|
||||
|
||||
/* process exchange register save: saves the current register
|
||||
set to the process pcb.
|
||||
set to the process pcb.
|
||||
NOTES:
|
||||
- adding "wait" arg and only saving base registers fixed Case 63
|
||||
*/
|
||||
@@ -3160,7 +3169,7 @@ static void pxregsave(unsigned short wait) {
|
||||
}
|
||||
|
||||
TRACE(T_PX, "pxregsave: saving registers owned by %o (wait=%d)\n", getcrs16(OWNERL), wait);
|
||||
|
||||
|
||||
/* NB: I think hardware might save the base registers in a predictable
|
||||
location in the PCB register save area, rather than compressed in a
|
||||
random order, because IIRC, Primos sometimes looks at a waiting
|
||||
@@ -3245,7 +3254,7 @@ static void ors(unsigned short pcbw) {
|
||||
debug, I wanted to make sure a process never owns 2 register sets */
|
||||
|
||||
if (ownerl == pcbw) {
|
||||
if (ownedx >= 0)
|
||||
if (ownedx >= 0)
|
||||
fatal("Process owns more than 1 register set!");
|
||||
ownedx = rx;
|
||||
} else if (ownerl == 0)
|
||||
@@ -3366,7 +3375,7 @@ static void dispatcher() {
|
||||
fatal(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* pcbp now points to the process we're going to run (pcbw is the
|
||||
16-bit word number that will go in OWNERL). By definition, this
|
||||
process should not be on any wait lists, so pcb.waitlist(seg)
|
||||
@@ -3471,7 +3480,7 @@ static void dispatcher() {
|
||||
TRACE(T_PX, "dispatch: abort flags for %o are %o\n", getcrs16(OWNERL), utempa);
|
||||
put16r0(0, pcbp+PCBABT);
|
||||
fault(PROCESSFAULT, utempa, 0);
|
||||
fatal("fault returned after process fault");
|
||||
fatal("fault returned after process fault");
|
||||
}
|
||||
|
||||
firstbdx = 1;
|
||||
@@ -3579,8 +3588,8 @@ static unsigned short ready (ea_t pcbp, unsigned short begend) {
|
||||
|
||||
resched = 0;
|
||||
if (level < getar16(PLA16) || (level == getar16(PLA16) && begend)) {
|
||||
regs.sym.plb = regs.sym.pla; /* Prime->Prime: no byte swap */
|
||||
regs.sym.pcbb = regs.sym.pcba; /* Prime->Prime: no byte swap */
|
||||
regs.sym.plb = regs.sym.pla; /* Prime->Prime: no byte swap */
|
||||
regs.sym.pcbb = regs.sym.pcba; /* Prime->Prime: no byte swap */
|
||||
putar16(PLA16, level);
|
||||
putar16(PCBA16, pcbw);
|
||||
resched = 1;
|
||||
@@ -3780,7 +3789,7 @@ static void lpsw() {
|
||||
if (getcrs16(MODALS) & 4) {
|
||||
TRACE(T_PX, "Segmentation enabled\n");
|
||||
gv.livereglim = 010;
|
||||
} else
|
||||
} else
|
||||
gv.livereglim = 040;
|
||||
if (getcrs16(MODALS) & 010) {
|
||||
TRACE(T_PX, "Process exchange enabled:\n");
|
||||
@@ -3823,7 +3832,7 @@ static void sssn() {
|
||||
put16(0, ea+i);
|
||||
}
|
||||
|
||||
/* if SSSN is from segment 14, it's probably the rev 23.4.Y2K
|
||||
/* if SSSN is from segment 14, it's probably the rev 23.4.Y2K
|
||||
system serial number check. Bypass the check loop. */
|
||||
|
||||
if (RPH == 014)
|
||||
@@ -4163,9 +4172,9 @@ static int add32(unsigned int a1, unsigned int a2, unsigned int a3, ea_t ea) {
|
||||
uresult = utemp; /* truncate result to result size */
|
||||
retval = uresult;
|
||||
if (utemp & 0x100000000LL) /* set L-bit if carry occurred */
|
||||
link = 020000;
|
||||
link = 020000;
|
||||
if (uresult == 0) /* set EQ? */
|
||||
eq = 0100;
|
||||
eq = 0100;
|
||||
if (((~a1 ^ a2) & (a1 ^ uresult) & 0x80000000) == 0) {
|
||||
if (*(int *)&uresult < 0)
|
||||
lt = 0200;
|
||||
@@ -4188,11 +4197,11 @@ static int add16(unsigned short a1, unsigned short a2, unsigned short a3, ea_t e
|
||||
uresult = a1; /* expand to higher precision */
|
||||
uresult += a2; /* double-precision add */
|
||||
uresult += a3; /* again, for subtract */
|
||||
keybits = (uresult & 0x10000) >> 3; /* set L-bit if carry occurred */
|
||||
keybits = (uresult & 0x10000) >> 3; /* set L-bit if carry occurred */
|
||||
uresult &= 0xFFFF; /* truncate result */
|
||||
retval = uresult; /* save result */
|
||||
if (uresult == 0) /* set EQ? */
|
||||
keybits |= 0100;
|
||||
keybits |= 0100;
|
||||
oflow = (((~a1 ^ a2) & (a1 ^ uresult) & 0x8000) != 0); /* overflow! */
|
||||
if (oflow)
|
||||
uresult = ~uresult;
|
||||
@@ -4366,7 +4375,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);
|
||||
}
|
||||
@@ -4448,7 +4457,9 @@ int main (int argc, char **argv) {
|
||||
|
||||
#include "dispatch.h"
|
||||
|
||||
noclock = 0;
|
||||
domemdump = 0;
|
||||
dolinecleararg = 0;
|
||||
bootarg = NULL;
|
||||
bootfile[0] = 0;
|
||||
gv.pmap32bits = 0;
|
||||
@@ -4465,9 +4476,15 @@ int main (int argc, char **argv) {
|
||||
while (i+1 < argc && argv[i+1][0] != '-')
|
||||
readloadmap(argv[++i], 1);
|
||||
|
||||
} else if (strcmp(argv[i],"-noclock") == 0) {
|
||||
noclock = 1;
|
||||
|
||||
} else if (strcmp(argv[i],"-memdump") == 0) {
|
||||
domemdump = 1;
|
||||
|
||||
} else if (strcmp(argv[i],"-dolineclear") == 0) {
|
||||
dolinecleararg = 1;
|
||||
|
||||
} else if (strcmp(argv[i],"-ss") == 0) {
|
||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||
sscanf(argv[++i],"%o", &templ);
|
||||
@@ -4606,6 +4623,10 @@ 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 (strcmp(argv[i],"fp") == 0)
|
||||
gv.traceflags |= T_FP;
|
||||
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)
|
||||
@@ -4676,7 +4697,7 @@ int main (int argc, char **argv) {
|
||||
regs.u32[i] = 0;
|
||||
|
||||
crsl = (void *)regs.sym.userregs[0]; /* first user register set */
|
||||
|
||||
|
||||
putcrs16(MODALS, 0); /* interrupts inhibited */
|
||||
newkeys(0);
|
||||
RP = 01000;
|
||||
@@ -4692,8 +4713,8 @@ int main (int argc, char **argv) {
|
||||
fatal("Can't allocate Prime memory block");
|
||||
}
|
||||
bzero(MEM, 64*1024*2); /* zero first 64K words */
|
||||
|
||||
/* if no maps were specified on the command line, look for ring0.map and
|
||||
|
||||
/* if no maps were specified on the command line, look for ring0.map and
|
||||
ring3.map in the current directory and read them */
|
||||
|
||||
if (numsyms == 0) {
|
||||
@@ -4894,7 +4915,7 @@ a filename, CPU registers and keys are loaded from the runfile header.\n\
|
||||
close(bootfd);
|
||||
|
||||
/* check we got it all */
|
||||
|
||||
|
||||
if (nw2 != nw*2) {
|
||||
printf("rvec[0]=%d, rvec[1]=%d, nw2=%d, nw=%d, nw*2=%d\n", rvec[0], rvec[1], nw2, nw, nw*2);
|
||||
fatal("Didn't read entire boot program");
|
||||
@@ -4905,7 +4926,7 @@ a filename, CPU registers and keys are loaded from the runfile header.\n\
|
||||
#if 1
|
||||
/* do a partial sysclr... move it here later if it fixes rev 19
|
||||
reboot from tape (ctrl-b) */
|
||||
|
||||
|
||||
putcrs16(MODALS, 0); /* interrupts inhibited */
|
||||
for (i=0; i < STLBENTS; i++)
|
||||
gv.stlb[i].seg = 0xFFFF; /* marker for invalid STLB entry */
|
||||
@@ -5131,7 +5152,7 @@ fetch:
|
||||
/* NOTE: Rev 21 Sys Arch Guide, 2nd Ed, pg 3-32 says:
|
||||
|
||||
"When bits 17 to 32 of the program counter contain a value within
|
||||
the ATR (address trap range) and the processor is reading an
|
||||
the ATR (address trap range) and the processor is reading an
|
||||
instruction, an address trap always occurs. The only exception
|
||||
to this is if the machine is operating in 32I mode."
|
||||
|
||||
@@ -5145,7 +5166,7 @@ fetch:
|
||||
NOTE 10/9/2007 (JW):
|
||||
iget16 has checks for RP < 0 to indicate an address trap, and all
|
||||
of the EA calculations can generate traps (and set the high-order
|
||||
bit) except 32I.
|
||||
bit) except 32I.
|
||||
|
||||
If it's a bad idea for RP to have the high-order bit set, then
|
||||
this code can be enabled, along with special handling in JMP,
|
||||
@@ -5244,7 +5265,7 @@ xec:
|
||||
|
||||
} else if ((getcrs16(KEYS) & 0016000) == 010000) { /* E32I */
|
||||
goto imode;
|
||||
|
||||
|
||||
} else if ((inst & 036000) == 030000) { /* check for pio in S/R modes, */
|
||||
pio(inst); /* before calculating EA */
|
||||
goto fetch;
|
||||
@@ -5516,7 +5537,7 @@ d_stac: /* 001200 */
|
||||
if (get16(ea) == getcrs16(B)) {
|
||||
put16(getcrs16(A), ea);
|
||||
SETEQ;
|
||||
} else
|
||||
} else
|
||||
CLEAREQ;
|
||||
goto fetch;
|
||||
|
||||
@@ -5526,7 +5547,7 @@ d_stlc: /* 001204 */
|
||||
if (get32(ea) == getcrs32(E)){
|
||||
put32(getcrs32(L), ea);
|
||||
SETEQ;
|
||||
} else
|
||||
} else
|
||||
CLEAREQ;
|
||||
goto fetch;
|
||||
|
||||
@@ -5656,7 +5677,7 @@ d_zmvd: /* 001115 */
|
||||
while (utempa--)
|
||||
*zcp2++ = *zcp1++;
|
||||
#else
|
||||
/* this causes error:
|
||||
/* this causes error:
|
||||
Coldstarting PRIMOS, Please wait...
|
||||
Unable to initialize gate segment. (GATE_INIT) */
|
||||
memcpy(zcp2, zcp1, utempa);
|
||||
@@ -6054,7 +6075,7 @@ d_wait: /* 000315 */
|
||||
pwait();
|
||||
goto fetch;
|
||||
|
||||
d_nfy: /* 1210 (nfye), 1211 (nfyb),
|
||||
d_nfy: /* 1210 (nfye), 1211 (nfyb),
|
||||
1214 (inen), 1215 (inbn), 1216 (inec), 1217 (inbc) */
|
||||
TRACE(T_FLOW, " NFY\n", inst);
|
||||
RESTRICT();
|
||||
@@ -6254,7 +6275,7 @@ d_svc: /* 000505 */
|
||||
TRACE(T_FLOW, " SVC\n");
|
||||
fault(SVCFAULT, 0, 0);
|
||||
fatal("Returned from SVC fault");
|
||||
|
||||
|
||||
d_cea: /* 000111 */
|
||||
TRACE(T_FLOW, " CEA\n");
|
||||
switch ((getcrs16(KEYS) & 016000) >> 10) {
|
||||
@@ -6293,13 +6314,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");
|
||||
@@ -6571,7 +6610,7 @@ d_bfgt: /* 0141611 */
|
||||
d_bix: /* 0141334 */
|
||||
TRACE(T_FLOW, " BIX\n");
|
||||
putcrs16(X, getcrs16(X) + 1);
|
||||
if (getcrs16(X) != 0)
|
||||
if (getcrs16(X) != 0)
|
||||
RPL = iget16(RP);
|
||||
else
|
||||
INCRP;
|
||||
@@ -6580,7 +6619,7 @@ d_bix: /* 0141334 */
|
||||
d_biy: /* 0141324 */
|
||||
TRACE(T_FLOW, " BIY\n");
|
||||
putcrs16(Y, getcrs16(Y) + 1);
|
||||
if (getcrs16(Y) != 0)
|
||||
if (getcrs16(Y) != 0)
|
||||
RPL = iget16(RP);
|
||||
else
|
||||
INCRP;
|
||||
@@ -6589,7 +6628,7 @@ d_biy: /* 0141324 */
|
||||
d_bdy: /* 0140724 */
|
||||
TRACE(T_FLOW, " BDY\n");
|
||||
putcrs16(Y, getcrs16(Y) - 1);
|
||||
if (getcrs16(Y) != 0)
|
||||
if (getcrs16(Y) != 0)
|
||||
RPL = iget16(RP);
|
||||
else
|
||||
INCRP;
|
||||
@@ -6598,7 +6637,7 @@ d_bdy: /* 0140724 */
|
||||
d_bdx: /* 0140734 */
|
||||
TRACE(T_FLOW, " BDX\n");
|
||||
putcrs16(X, getcrs16(X) - 1);
|
||||
if (getcrs16(X) == 0)
|
||||
if (getcrs16(X) == 0)
|
||||
INCRP;
|
||||
else {
|
||||
m = iget16(RP);
|
||||
@@ -6608,7 +6647,7 @@ d_bdx: /* 0140734 */
|
||||
long delayusec, actualmsec;
|
||||
|
||||
/* for BDX * loop (backstop process mainly), we want to change
|
||||
this to a long sleep so that the emulation host's CPU isn't
|
||||
this to a long sleep so that the emulation host's CPU isn't
|
||||
pegged the whole time the emulator is running.
|
||||
|
||||
So first, check to see if any device times expire sooner than
|
||||
@@ -6649,7 +6688,7 @@ d_bdx: /* 0140734 */
|
||||
if (delayusec > 1000) {
|
||||
if (gettimeofday(&tv0, NULL) != 0)
|
||||
fatal("em: gettimeofday 0 failed");
|
||||
|
||||
|
||||
/* for some reason, the SIGTERM signal handler gets reset
|
||||
during emulator initialization; this re-installs it */
|
||||
|
||||
@@ -6672,7 +6711,7 @@ d_bdx: /* 0140734 */
|
||||
TRACEA(" BDX loop at %o/%o, owner=%o, utempl=%d, wanted %d ms, got %d ms\n", gv.prevpc>>16, gv.prevpc&0xffff, getcrs16(OWNERL), utempl, delayusec/1000, actualmsec);
|
||||
}
|
||||
#endif
|
||||
/* do timer bookkeeping that would have occurred if we had
|
||||
/* do timer bookkeeping that would have occurred if we had
|
||||
actually looped on BDX utempl times */
|
||||
|
||||
for (i=0; i<64; i++)
|
||||
@@ -6788,14 +6827,14 @@ d_caz: /* 0140214 */
|
||||
d_irx: /* 0140114 */
|
||||
TRACE(T_FLOW, " IRX\n");
|
||||
putcrs16(X, getcrs16(X) + 1);
|
||||
if (getcrs16(X) == 0)
|
||||
if (getcrs16(X) == 0)
|
||||
INCRP;
|
||||
goto fetch;
|
||||
|
||||
d_drx: /* 0140210 */
|
||||
TRACE(T_FLOW, " DRX\n");
|
||||
putcrs16(X, getcrs16(X) - 1);
|
||||
if (getcrs16(X) == 0)
|
||||
if (getcrs16(X) == 0)
|
||||
INCRP;
|
||||
goto fetch;
|
||||
|
||||
@@ -7266,7 +7305,7 @@ d_tstq: /* 0141757 */
|
||||
|
||||
/* XXX: hack for CPU.FAULT; not sure how to determine
|
||||
whether an instruction is illegal or unimplemented */
|
||||
|
||||
|
||||
fault(ILLINSTFAULT, RPL, RP);
|
||||
fatal("Return from 0141700 fault");
|
||||
|
||||
@@ -8403,7 +8442,7 @@ dfcmdr:
|
||||
if (get32(ea) == getgr32(dr+1)) {
|
||||
put32(getgr32(dr), ea);
|
||||
SETEQ;
|
||||
} else
|
||||
} else
|
||||
CLEAREQ;
|
||||
break;
|
||||
|
||||
@@ -8413,7 +8452,7 @@ dfcmdr:
|
||||
if (get16(ea) == (getcrs16(dr*2+1))) {
|
||||
put16(getgr16(dr), ea);
|
||||
SETEQ;
|
||||
} else
|
||||
} else
|
||||
CLEAREQ;
|
||||
break;
|
||||
|
||||
@@ -8702,7 +8741,7 @@ dfcmdr:
|
||||
tempa1 = getgr32(FAC0+dr+1) & 0xffff;
|
||||
tempa2 = immu64 & 0xffff;
|
||||
if (abs(tempa1-tempa2) < 48)
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1+tempd2, (long long *)(crsl+FAC0+dr), 0))
|
||||
CLEARC;
|
||||
@@ -8724,7 +8763,7 @@ dfcmdr:
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC0+dr))
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1+tempd2, (long long *)(crsl+FAC0+dr), 0))
|
||||
CLEARC;
|
||||
@@ -8816,7 +8855,7 @@ dfcmdr:
|
||||
tempa1 = getgr32(FAC0+dr+1) & 0xffff;
|
||||
tempa2 = immu64 & 0xffff;
|
||||
if (abs(tempa1-tempa2) < 48)
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1-tempd2, (long long *)(crsl+FAC0+dr), 0))
|
||||
CLEARC;
|
||||
@@ -8842,7 +8881,7 @@ dfcmdr:
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC0+dr))
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
if (prieee8(getfr64(dr), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1-tempd2, (long long *)(crsl+FAC0+dr), 0))
|
||||
CLEARC;
|
||||
@@ -8866,7 +8905,7 @@ dfcmdr:
|
||||
immu64 = ((immu64 << 32) & 0xffffff0000000000LL) | (immu64 & 0xff);
|
||||
}
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(dr), &tempd1)
|
||||
&& ieeepr8(tempd1*tempd2, (long long *)(crsl+FAC0+dr), 0))
|
||||
CLEARC;
|
||||
@@ -8886,7 +8925,7 @@ dfcmdr:
|
||||
if (*(int *)&ea >= 0)
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(dr), &tempd1)
|
||||
&& ieeepr8(tempd1*tempd2, (long long *)(crsl+FAC0+dr), 0))
|
||||
CLEARC;
|
||||
@@ -8964,7 +9003,7 @@ dfcmdr:
|
||||
}
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC0+dr))
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(dr), &tempd1)
|
||||
&& ieeepr8(tempd1/tempd2, (long long *)(crsl+FAC0+dr), 1))
|
||||
CLEARC;
|
||||
@@ -8984,7 +9023,7 @@ dfcmdr:
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC0+dr))
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(dr), &tempd1)
|
||||
&& ieeepr8(tempd1/tempd2, (long long *)(crsl+FAC0+dr), 1))
|
||||
CLEARC;
|
||||
@@ -9528,7 +9567,7 @@ d_adddad: /* 00600 (R-mode) */
|
||||
putcrs16(KEYS, getcrs16(KEYS) | 020000);
|
||||
/* NOTE: this EQ test prevents reusing the ADD code :( */
|
||||
if (getcrs32s(L) == 0) /* set EQ? */
|
||||
SETEQ;
|
||||
SETEQ;
|
||||
if (((~utempa ^ m) & (utempa ^ getcrs16(A))) & 0x8000) {
|
||||
if (getcrs32s(L) >= 0)
|
||||
SETLT;
|
||||
@@ -9563,7 +9602,7 @@ d_subdsb: /* 00700 */
|
||||
if (utempl & 0x10000) /* set L-bit if carry */
|
||||
putcrs16(KEYS, getcrs16(KEYS) | 020000);
|
||||
if (getcrs32s(L) == 0) /* set EQ? */
|
||||
SETEQ;
|
||||
SETEQ;
|
||||
if (((utempa ^ m) & (utempa ^ getcrs16(A))) & 0x8000) {
|
||||
if (getcrs32s(L) >= 0)
|
||||
SETLT;
|
||||
@@ -9615,9 +9654,9 @@ d_cas: /* 01100 */
|
||||
utempl += 1;
|
||||
putcrs16(A, utempl); /* truncate results */
|
||||
if (utempl & 0x10000) /* set L-bit if carry */
|
||||
putcrs16(KEYS, getcrs16(KEYS) | 020000);
|
||||
putcrs16(KEYS, getcrs16(KEYS) | 020000);
|
||||
if (getcrs16(A) == 0) /* set EQ? */
|
||||
SETEQ;
|
||||
SETEQ;
|
||||
if (((utempa ^ m) & (utempa ^ getcrs16(A))) & 0x8000) {
|
||||
if (getcrs16s(A) >= 0)
|
||||
SETLT;
|
||||
@@ -9914,7 +9953,7 @@ d_fad: /* 00601 */
|
||||
tempa1 = getcrs16(FEXP);
|
||||
tempa2 = immu64 & 0xffff;
|
||||
if (abs(tempa1-tempa2) < 48)
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1+tempd2, (long long *)(crsl+FAC1), 0))
|
||||
CLEARC;
|
||||
@@ -9942,7 +9981,7 @@ d_fdv: /* 01701 */
|
||||
immu64 = ((immu64 << 32) & 0xffffff0000000000LL) | (immu64 & 0xff);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC1))
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(2), &tempd1)
|
||||
&& ieeepr8(tempd1/tempd2, (long long *)(crsl+FAC1), 1))
|
||||
CLEARC;
|
||||
@@ -9967,7 +10006,7 @@ d_fmp: /* 01601 */
|
||||
immu64 = get32(ea);
|
||||
immu64 = ((immu64 << 32) & 0xffffff0000000000LL) | (immu64 & 0xff);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(2), &tempd1)
|
||||
&& ieeepr8(tempd1*tempd2, (long long *)(crsl+FAC1), 0))
|
||||
CLEARC;
|
||||
@@ -9988,7 +10027,7 @@ d_fsb: /* 00701 */
|
||||
tempa1 = getcrs16(FEXP);
|
||||
tempa2 = immu64 & 0xffff;
|
||||
if (abs(tempa1-tempa2) < 48)
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1-tempd2, (long long *)(crsl+FAC1), 0))
|
||||
CLEARC;
|
||||
@@ -10027,7 +10066,7 @@ d_dfad: /* 0602 */
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC1))
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1+tempd2, (long long *)(crsl+FAC1), 0)) {
|
||||
CLEARC;
|
||||
@@ -10053,7 +10092,7 @@ d_dfdv: /* 01702 */
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC1))
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(2), &tempd1)
|
||||
&& ieeepr8(tempd1/tempd2, (long long *)(crsl+FAC1), 1)) {
|
||||
CLEARC;
|
||||
@@ -10082,7 +10121,7 @@ d_dfmp: /* 01602 */
|
||||
if (getgr32s(FAC1)) {
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
if (prieee8(immu64, &tempd2)
|
||||
&& prieee8(getfr64(2), &tempd1)
|
||||
&& ieeepr8(tempd1*tempd2, (long long *)(crsl+FAC1), 0)) {
|
||||
CLEARC;
|
||||
@@ -10101,7 +10140,7 @@ d_dfsb: /* 0702 */
|
||||
immu64 = get64(ea);
|
||||
if (immu64 & 0xFFFFFFFF00000000LL)
|
||||
if (getgr32s(FAC1))
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
if (prieee8(getfr64(2), &tempd1)
|
||||
&& prieee8(immu64, &tempd2)
|
||||
&& ieeepr8(tempd1-tempd2, (long long *)(crsl+FAC1), 0)) {
|
||||
CLEARC;
|
||||
|
||||
44
emdev.h
44
emdev.h
@@ -51,7 +51,7 @@
|
||||
'50 = #1 HSSMLC/MDLC (synchronous comm)
|
||||
'51 = #2 HSSMLC/MDLC
|
||||
* '52 = #3 AMLC or ICS1
|
||||
* '53 = #2 AMLC
|
||||
* '53 = #2 AMLC
|
||||
* '54 = #1 AMLC
|
||||
'55 = MACI autocall unit
|
||||
'56 = old SMLC (RTOS User Guide, A-1 & Hacker's Guide)
|
||||
@@ -229,7 +229,7 @@ int devnone (int class, int func, int device) {
|
||||
OCP '0604 = enable transmit DMA/C
|
||||
OCP '0704 = reset transmit interrupt mask and DMA/C enable
|
||||
OCP '1004 = Full duplex; software must echo
|
||||
OCP '1104 = output a sync pulse (diagnostics)
|
||||
OCP '1104 = output a sync pulse (diagnostics)
|
||||
OCP '1204 = Prime normal, independent xmit and recv w/echoplex
|
||||
OCP '1304 = Self test mode (internally connects transmitter to receiver)
|
||||
OCP '1504 = Set both xmit & rcv interrupt masks
|
||||
@@ -302,7 +302,7 @@ int devasr (int class, int func, int device) {
|
||||
int doblock;
|
||||
time_t unixtime;
|
||||
struct tm *tms;
|
||||
|
||||
|
||||
doblock = BLOCKIO;
|
||||
|
||||
switch (class) {
|
||||
@@ -330,7 +330,7 @@ int devasr (int class, int func, int device) {
|
||||
perror(" unable to get tty attributes");
|
||||
fatal(NULL);
|
||||
}
|
||||
|
||||
|
||||
/* save initial terminal setup to restore when exiting */
|
||||
|
||||
origterminfo = terminfo;
|
||||
@@ -497,7 +497,7 @@ readasr:
|
||||
goto readasr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* if doing local echo, do xon/xoff processing here. If Unix
|
||||
does it, the emulator might block on a console write. If
|
||||
the console is running full-duplex (no local echo), we can
|
||||
@@ -650,7 +650,7 @@ readasr:
|
||||
|
||||
/* Device '14 - magtape controller #1
|
||||
|
||||
NOTES:
|
||||
NOTES:
|
||||
|
||||
This code only supports 1 tape controller (4 units), but could be
|
||||
extended to support 2 controllers (eg, see disk controller code)
|
||||
@@ -863,7 +863,7 @@ fmterr:
|
||||
*mtstat |= 0x100; /* set filemark status */
|
||||
goto repo;
|
||||
}
|
||||
|
||||
|
||||
/* ignore attempts to backspace over error records. This will
|
||||
cause Magsav to read the next record instead, and it may
|
||||
recover. Re-reading the error record 10 times won't help! */
|
||||
@@ -881,7 +881,7 @@ fmterr:
|
||||
}
|
||||
|
||||
/* read leading reclen again to make sure we're positioned correctly */
|
||||
|
||||
|
||||
n = read(fd, buf, 4);
|
||||
if (n == -1) goto readerr;
|
||||
if (n != 4) {
|
||||
@@ -974,7 +974,7 @@ int devmt (int class, int func, int device) {
|
||||
enabled = 1;
|
||||
if (interrupting == 1) /* if interrupt is pending */
|
||||
devpoll[device] = 10; /* try to interrupt soon */
|
||||
|
||||
|
||||
} else if (func == 016) { /* reset interrupt mask */
|
||||
enabled = 0;
|
||||
|
||||
@@ -1092,7 +1092,7 @@ int devmt (int class, int func, int device) {
|
||||
} else
|
||||
unit[u].mtstat = 0x00C8; /* Ready, Online, BOT */
|
||||
}
|
||||
|
||||
|
||||
/* "select only" is ignored. On a real tape controller, this
|
||||
blocks (I think) if the previous tape operation is in progress */
|
||||
|
||||
@@ -1276,12 +1276,12 @@ int devmt (int class, int func, int device) {
|
||||
}
|
||||
IOSKIP;
|
||||
break;
|
||||
|
||||
|
||||
} else if (func == 02) {
|
||||
ready = 1;
|
||||
if (getcrs16(A) & 0x8000) { /* status word 1 */
|
||||
datareg = unit[usel].mtstat;
|
||||
|
||||
|
||||
/* if the tape was rewinding, return rewinding status once, then
|
||||
change it to BOT */
|
||||
|
||||
@@ -1413,7 +1413,9 @@ void initclock(ea_t datnowea) {
|
||||
unixtime = time(NULL);
|
||||
tms = localtime(&unixtime);
|
||||
datnow = tms->tm_year<<25 | (tms->tm_mon+1)<<21 | tms->tm_mday<<16 | ((tms->tm_hour*3600 + tms->tm_min*60 + tms->tm_sec)/4);
|
||||
put32r0(datnow, datnowea);
|
||||
if (! noclock) {
|
||||
put32r0(datnow, datnowea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1438,7 +1440,7 @@ int devcp (int class, int func, int device) {
|
||||
|
||||
case -1:
|
||||
|
||||
/* if -map is used, lookup DATNOW symbol and set the 32-bit
|
||||
/* if -map is used, lookup DATNOW symbol and set the 32-bit
|
||||
Primos time value (DATNOW+TIMNOW) */
|
||||
|
||||
datnowea = 0;
|
||||
@@ -1455,10 +1457,10 @@ int devcp (int class, int func, int device) {
|
||||
;
|
||||
|
||||
} else if (func == 01) { /* ack PIC interrupt */
|
||||
;
|
||||
;
|
||||
|
||||
} else if (func == 02) { /* stop LFC (IO.PNC DIAG) */
|
||||
;
|
||||
;
|
||||
|
||||
} else if (func == 04) { /* does something on VCP during boot */
|
||||
;
|
||||
@@ -1581,7 +1583,7 @@ int devcp (int class, int func, int device) {
|
||||
previnstcount = gv.instcount;
|
||||
if (datnowea != 0)
|
||||
initclock(datnowea);
|
||||
}
|
||||
}
|
||||
elapsedms = (tv.tv_sec-start_tv.tv_sec)*1000.0 + (tv.tv_usec-start_tv.tv_usec)/1000.0;
|
||||
targetticks = elapsedms/(-clkpic*clkrate/1000);
|
||||
#if 0
|
||||
@@ -1595,7 +1597,7 @@ int devcp (int class, int func, int device) {
|
||||
available (no Primos maps), then we have to tick our way to
|
||||
the correct time. In addition to lowering overhead, slower
|
||||
clock tick rates make catching up much faster.
|
||||
|
||||
|
||||
When ticking faster, we need to be careful not to tick too
|
||||
fast, because that will cause timed events like disk I/O to
|
||||
timeout prematurely. With rev 20 Primos, setting the
|
||||
@@ -1812,7 +1814,7 @@ int devdisk (int class, int func, int device) {
|
||||
dc[dx].unit[u].modrecs = NULL;
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
||||
case 0:
|
||||
TRACE(T_INST|T_DIO, " OCP '%2o%2o\n", func, device);
|
||||
if (func == 016) { /* reset interrupt */
|
||||
@@ -2017,7 +2019,7 @@ int devdisk (int class, int func, int device) {
|
||||
}
|
||||
dmaaddr = ((getar16(REGDMX16+dmareg) & 3)<<16) | getar16(REGDMX16+dmareg+1);
|
||||
TRACE(T_INST|T_DIO, " DMA channels: nch-1=%d, ['%o]='%o, ['%o]='%o, nwords=%d\n", dc[dx].dmanch, dc[dx].dmachan, swap16(regs.sym.regdmx[dmareg]), dc[dx].dmachan+1, dmaaddr, dmanw);
|
||||
|
||||
|
||||
if (order == 5) { /* read */
|
||||
if (getcrs16(MODALS) & 020) /* mapped read */
|
||||
if ((dmaaddr & 01777) || dmanw > 1024)
|
||||
@@ -2078,7 +2080,7 @@ int devdisk (int class, int func, int device) {
|
||||
}
|
||||
TRACE(T_INST|T_DIO, " seek track %d, restore=%d, clear=%d\n", track, (m1 & 0100000) != 0, (m1 & 040000) != 0);
|
||||
#if 0
|
||||
/* this has been disabled because SCSI drives sometimes seek to
|
||||
/* this has been disabled because SCSI drives sometimes seek to
|
||||
track 512 (special meaning in controller?) */
|
||||
|
||||
if (track > dc[dx].unit[u].maxtrack) {
|
||||
|
||||
84
fp.h
84
fp.h
@@ -40,6 +40,7 @@ http://tima-cmp.imag.fr/~guyot/Cours/Oparithm/english/Op_Ar2.htm
|
||||
|
||||
inline void getdp (unsigned long long p, long long *frac64, int *exp32) {
|
||||
|
||||
TRACE(T_FP, " getdp(%016llx)\n", p);
|
||||
*frac64 = p & 0xFFFFFFFFFFFF0000LL; /* unpack fraction */
|
||||
*exp32 = (short) (p & 0xFFFFLL); /* unpack SIGNED exponent */
|
||||
}
|
||||
@@ -59,22 +60,29 @@ int prieee8(unsigned long long dp, double *d) {
|
||||
/* unpack Prime DPFP */
|
||||
|
||||
getdp (dp, &frac64, &exp32);
|
||||
TRACE(T_FP, " prieee8: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
||||
|
||||
/* if negative, change to sign-magnitude */
|
||||
|
||||
sign = 0;
|
||||
if (frac64 < 0) {
|
||||
TRACE(T_FP, " prieee8: changing to sign-magnitude\n");
|
||||
|
||||
/* special case: negative power of 2 */
|
||||
|
||||
if (frac64 == 0x8000000000000000LL) {
|
||||
TRACE(T_FP, " prieee8: frac is negative power of 2\n");
|
||||
exp32 += (1023-128);
|
||||
if (exp32 < 0 || exp32 > 0x7fe)
|
||||
{
|
||||
TRACE(T_FP, " prieee8: exp %x out of range\n", exp32);
|
||||
return 0;
|
||||
}
|
||||
frac64 |= ((long long)exp32 << 52);
|
||||
*d = *(double *)&frac64;
|
||||
return 1;
|
||||
} else {
|
||||
TRACE(T_FP, " prieee8: frac is just negative\n");
|
||||
sign = 0x8000000000000000LL;
|
||||
frac64 = -frac64;
|
||||
}
|
||||
@@ -82,13 +90,15 @@ int prieee8(unsigned long long dp, double *d) {
|
||||
/* special case: zero */
|
||||
|
||||
} else if (frac64 == 0) {
|
||||
TRACE(T_FP, " prieee8: frac is 0\n");
|
||||
*d = 0.0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* normalize positive fraction until bit 2 is 1 */
|
||||
|
||||
while ((frac64 & 0x4000000000000000LL) == 0) {
|
||||
TRACE(T_FP, " prieee8: normalizing positive fraction\n");
|
||||
frac64 = frac64 << 1;
|
||||
exp32--;
|
||||
}
|
||||
@@ -98,7 +108,10 @@ int prieee8(unsigned long long dp, double *d) {
|
||||
exp32 += (1023-128) - 1;
|
||||
#if 1
|
||||
if (exp32 < 0 || exp32 > 0x7fe)
|
||||
{
|
||||
TRACE(T_FP, " prieee8: exponent %x out of range\n", exp32);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (exp32 < 0) {
|
||||
*d = 0.0;
|
||||
@@ -113,6 +126,7 @@ int prieee8(unsigned long long dp, double *d) {
|
||||
/* pack into an IEEE DPFP, losing the leading 1 bit in the process */
|
||||
|
||||
frac64 = sign | ((long long)exp32 << 52) | ((frac64 >> 10) & 0xfffffffffffffLL);
|
||||
TRACE(T_FP, " prieee8: packed ieee dpfp %016llx\n", frac64);
|
||||
*d = *(double *)&frac64;
|
||||
return 1;
|
||||
}
|
||||
@@ -134,7 +148,7 @@ retry:
|
||||
neg = frac64 < 0;
|
||||
exp32 = (frac64 >> 52) & 0x7ff;
|
||||
frac64 &= 0xfffffffffffffLL;
|
||||
//printf("dp=%llx, neg=%d, frac64=%llx, exp32=%d, \n", *(long long *)dp, neg, frac64, exp32);
|
||||
TRACE(T_FP, "d=%016llx, neg=%x, frac64=%016llx, exp32=%08x, \n", (long long)d, neg, frac64, exp32);
|
||||
|
||||
/* special case: NaN & +-infinity */
|
||||
|
||||
@@ -159,12 +173,21 @@ retry:
|
||||
and subnormal */
|
||||
|
||||
if (exp32 != 0) /* typical IEEE normalized */
|
||||
{
|
||||
TRACE(T_FP, " ieeepr8: is normalized\n");
|
||||
frac64 |= 0x10000000000000LL;
|
||||
else if (frac64 == 0) { /* IEEE +-0.0 (zero exp+frac) */
|
||||
}
|
||||
else if (frac64 == 0) /* IEEE +-0.0 (zero exp+frac) */
|
||||
{
|
||||
TRACE(T_FP, " ieeepr8: zero exp and frac\n");
|
||||
*p = 0; /* IEEE and Prime zero are the same */
|
||||
return okay;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE(T_FP, " ieeepr8: subnormal value\n");
|
||||
; /* subnormal: no hidden 1 bit */
|
||||
}
|
||||
|
||||
/* adjust exponent, change sign-magnitude to 2's complement,
|
||||
and shift fraction into Prime placement (high 48 bits) */
|
||||
@@ -173,12 +196,14 @@ retry:
|
||||
if (neg)
|
||||
frac64 = -frac64;
|
||||
frac64 <<= 10;
|
||||
TRACE(T_FP, " ieeepr8: de-biased prime-ised frac %016llx exp %08x\n", frac64, exp32);
|
||||
|
||||
/* normalize Prime DPFP */
|
||||
|
||||
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
||||
frac64 = frac64 << 1;
|
||||
exp32--;
|
||||
TRACE(T_FP, " ieeepr8: normalized prime frac %016llx exp %08x\n", frac64, exp32);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -204,8 +229,11 @@ retry:
|
||||
|
||||
if (round)
|
||||
if ((frac64 & 0x8000) && ((frac64 & 0x7fffffffffff0000LL) != 0x7fffffffffff0000LL))
|
||||
{
|
||||
/* XXX: should this be a subtract for negative numbers? */
|
||||
frac64 += 0x10000;
|
||||
TRACE(T_FP, " ieeepr8: rounded frac %016llx\n", frac64);
|
||||
}
|
||||
|
||||
*p = swap64((frac64 & 0xffffffffffff0000LL) | (exp32 & 0xffff));
|
||||
return okay;
|
||||
@@ -260,6 +288,7 @@ unsigned long long dfcm (unsigned long long dp, int *oflow) {
|
||||
CLEARC;
|
||||
*oflow = 0;
|
||||
getdp(dp, &frac64, &exp32);
|
||||
TRACE(T_FP, " dfcm: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
||||
if (frac64 != 0) { /* can't normalize zero */
|
||||
if (frac64 == 0x8000000000000000LL) { /* overflow case? */
|
||||
frac64 = 0x4000000000000000LL; /* complement power of 2 */
|
||||
@@ -290,6 +319,7 @@ unsigned long long norm(unsigned long long dp, int *oflow) {
|
||||
|
||||
*oflow = 0;
|
||||
getdp(dp, &frac64, &exp32);
|
||||
TRACE(T_FP, " norm: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
||||
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
||||
frac64 = frac64 << 1;
|
||||
exp32--;
|
||||
@@ -314,11 +344,16 @@ unsigned long long frn(unsigned long long dp, int *oflow) {
|
||||
|
||||
*oflow = 0;
|
||||
getdp(dp, &frac64, &exp32);
|
||||
TRACE(T_FP, " frn: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
||||
if (frac64 == 0)
|
||||
{
|
||||
TRACE(T_FP, " frn: returning 0\n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
doround1 = ((frac64 & 0x18000000000LL) != 0);
|
||||
doround2 = ((frac64 & 0x8000000000LL) != 0) && ((frac64 & 0x7FFFFF0000LL) != 0);
|
||||
TRACE(T_FP, " frn: doround1 %x doround2 %x\n", doround1, doround2);
|
||||
if (doround1 || doround2) {
|
||||
frac64 &= 0xFFFFFF0000000000LL;
|
||||
if (frac64 != 0x7FFFFF0000000000LL)
|
||||
@@ -329,8 +364,10 @@ unsigned long long frn(unsigned long long dp, int *oflow) {
|
||||
}
|
||||
frac64 |= (exp32 & 0xFFFF);
|
||||
frac64 = norm(frac64, oflow);
|
||||
TRACE(T_FP, " frn: rounded frac %016llx\n", frac64);
|
||||
return frac64;
|
||||
}
|
||||
TRACE(T_FP, " frn: dp %016llx\n", dp);
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
@@ -356,26 +393,37 @@ int fcs (unsigned long long fac, int fop) {
|
||||
fop = fop & 0xffffff00;
|
||||
if (fop == 0) /* fix dirty zero */
|
||||
fopexp = 0;
|
||||
TRACE(T_FP, " fcs: FAC: %016llx %04x; op: %016llx %04x\n", templ, facexp, fop, fopexp);
|
||||
if ((templ & 0x80000000) == (fop & 0x80000000)) { /* compare signs */
|
||||
if (facexp == fopexp) /* compare exponents */
|
||||
if (templ == fop) { /* compare fractions */
|
||||
TRACE(T_FP, " fcs: frac cmp returning eq / skip 1\n");
|
||||
SETEQ;
|
||||
return 1;
|
||||
} else if (templ < fop) { /* compare fractions */
|
||||
TRACE(T_FP, " fcs: frac cmp returning lt / skip 2\n");
|
||||
SETLT; /* FAC < operand */
|
||||
return 2;
|
||||
} else
|
||||
} else {
|
||||
TRACE(T_FP, " fcs: frac cmp returning gt / skip 0\n");
|
||||
return 0; /* FAC > operand */
|
||||
}
|
||||
else if (facexp < fopexp) { /* compare exponents */
|
||||
TRACE(T_FP, " fcs: exp cmp returning lt / skip 2\n");
|
||||
SETLT; /* FAC < operand */
|
||||
return 2;
|
||||
} else
|
||||
} else {
|
||||
TRACE(T_FP, " fcs: exp cmp returning gt / skip 0\n");
|
||||
return 0;
|
||||
}
|
||||
} else if (templ & 0x80000000) {
|
||||
TRACE(T_FP, " fcs: sign cmp returning lt / skip 2\n");
|
||||
SETLT; /* FAC < operand */
|
||||
return 2;
|
||||
} else
|
||||
} else {
|
||||
TRACE(T_FP, " fcs: sign cmp returning gt / skip 0\n");
|
||||
return 0; /* FAC > operand */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -386,7 +434,7 @@ int fcs (unsigned long long fac, int fop) {
|
||||
|
||||
NOTE: This code doesn't pass Prime diagnostics for higher model
|
||||
CPU's, I'm guessing because comparison is implemented as subtract,
|
||||
and we can't do that because numbers with huge exponents (and
|
||||
and we can't do that because numbers with huge exponents (and
|
||||
Prime ASCII characters in the DAC) won't convert to IEEE.
|
||||
*/
|
||||
|
||||
@@ -404,27 +452,35 @@ int dfcs (unsigned long long fac, long long fop) {
|
||||
fop = fop & 0xffffffffffff0000LL;
|
||||
if (fop == 0) /* fix dirty zero */
|
||||
fopexp = 0;
|
||||
#if 0
|
||||
printf("dfcs: FAC: %016llx %04x; op: %016llx %04x\n", templl, facexp, fop, fopexp);
|
||||
#endif
|
||||
TRACE(T_FP, " dfcs: FAC: %016llx %04x; op: %016llx %04x\n", templl, facexp, fop, fopexp);
|
||||
if ((templl & 0x8000000000000000LL) == (fop & 0x8000000000000000LL)) { /* compare signs */
|
||||
if (facexp == fopexp) /* compare exponents */
|
||||
if (templl == fop) { /* compare fractions */
|
||||
TRACE(T_FP, " dfcs: frac cmp returning eq / skip 1\n");
|
||||
SETEQ;
|
||||
return 1;
|
||||
} else if (templl < fop) { /* compare fractions */
|
||||
TRACE(T_FP, " dfcs: frac cmp returning lt / skip 2\n");
|
||||
SETLT; /* FAC < operand */
|
||||
return 2;
|
||||
} else
|
||||
} else {
|
||||
TRACE(T_FP, " dfcs: frac cmp returning gt / skip 0\n");
|
||||
return 0; /* FAC > operand */
|
||||
}
|
||||
else if (facexp < fopexp) { /* compare exponents */
|
||||
TRACE(T_FP, " dfcs: exp cmp returning lt / skip 2\n");
|
||||
SETLT; /* FAC < operand */
|
||||
return 2;
|
||||
} else
|
||||
} else {
|
||||
TRACE(T_FP, " dfcs: exp cmp returning eq / skip 1\n");
|
||||
return 0;
|
||||
}
|
||||
} else if (templl & 0x8000000000000000LL) {
|
||||
TRACE(T_FP, " dfcs: sign cmp returning lt / skip 2\n");
|
||||
SETLT; /* FAC < operand */
|
||||
return 2;
|
||||
} else
|
||||
} else {
|
||||
TRACE(T_FP, " dfcs: sign cmp returning gt / skip 0\n");
|
||||
return 0; /* FAC > operand */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* utextp.c, Jim Wilcoxson, March 16, 2005
|
||||
Reads a Unix text file and converts it to a compressed Prime text file.
|
||||
Reads a Unix text file and converts it to a compressed Prime text file.
|
||||
This means:
|
||||
- turn high bit on
|
||||
- expand Unix tabs to spaces
|
||||
@@ -29,7 +29,7 @@ main () {
|
||||
else { /* not a space character */
|
||||
while (space) { /* dump held-back spaces first */
|
||||
if (space < 3) { /* write regular spaces */
|
||||
putchar(' ');
|
||||
putchar(0240);
|
||||
space--;
|
||||
n++;
|
||||
} else { /* write compressed spaces */
|
||||
|
||||
Reference in New Issue
Block a user