1
0
mirror of https://github.com/prirun/p50em.git synced 2026-03-13 13:30:56 +00:00

33 Commits

Author SHA1 Message Date
Dennis Boone
256c72ca64 Install git in the vm so the version stamping works. 2021-03-19 01:42:51 -04:00
Dennis Boone
975cc951f8 Really? No "latest" tag or release or whatever, have to use a
numeric version?
2021-03-19 01:34:13 -04:00
Dennis Boone
29fbc31df6 Can the packaging be outside the vm thing? 2021-03-19 01:30:30 -04:00
Dennis Boone
f72b67b876 FreeBSD build, attempt 1. 2021-03-19 01:27:25 -04:00
Dennis Boone
df6529c505 Make these manual. 2021-03-19 01:16:12 -04:00
Dennis Boone
8782e6a63e MacOS builder. 2021-03-19 01:13:11 -04:00
Dennis Boone
88a43363e1 Put repo_token back in
Not sure what this really wants, the action doco doesn't explain it _at all_.
2021-03-19 00:58:53 -04:00
Dennis Boone
9fa1c77bad Flush out the auto-build. No clue if this will work. 2021-03-18 11:58:04 -04:00
Dennis Boone
2d8397d1a4 Create linuxbuild.yml
See if we can build release binaries.
2021-03-18 11:45:44 -04:00
Dennis Boone
244f2f49a2 Remove now-inaccurate comment. 2021-02-21 00:35:31 -05:00
Dennis Boone
af2b015383 Fix for problem where PASCAL install test crashes.
It appears that the emulator needs to check for faulted pointers
after indirection in APs used in e.g. EAFA.  PASCAL triggers this
issue by using EAFA on an indirect pointer to a DYNT.  A two cycle
fault check is done other places, and the approach is repeated here.
2021-02-21 00:06:38 -05:00
Dennis Boone
902f535120 Merge remote-tracking branch 'refs/remotes/origin/master' 2021-02-17 18:11:03 -05:00
Dennis Boone
25febc3947 Merge remote-tracking branch 'refs/remotes/origin/master' 2021-02-11 13:01:51 -05:00
Dennis Boone
84afd8da7b Add an editorconfig file. 2021-02-11 13:01:28 -05:00
Dennis Boone
d6d01cd05c Workaround for locked up AMLC lines
As it was in the real world, especially with dialup ports, it is possible
for an emulator AMLC line to get blocked by stray flow control characters.
The blocked port may appear dead to the next user to connect, if they are
not "serial savvy" enough to try sending an XON character.

A large number of vulnerability scanners have found and have been hitting
the public emulators, injecting HTTP transactions or worse into the AMLC
ports and often locking all of them daily.

This workaround injects an XON (DC1, 0221) and a line kill character as
extracted from the DEFKIL field in FIGCOM, into the AMLC line when a new
connection is received.

There is a -dolineclear command line switch to enable the behavior.
2021-02-07 00:37:15 -05:00
Dennis Boone
ea2edd89de Fix terminal i/o issue in d_hlt
Due to the configuration of the tty, the getchar() call in d_hlt
returns nothing.  Work around this in the same way the SOC console
code does, by opening it on a separate unit, and reading from that
instead.  Without this fix, the code which looks for certain halt
cases and offers "continue or exit" just spins, printing its message
and getting no input.
2021-02-06 17:11:55 -05:00
Dennis Boone
3d71fd85f0 Update copyrights. 2021-02-03 18:51:34 -05:00
Dennis Boone
5d119bb2c5 Update README.md
Github discussions.
2021-01-21 14:24:49 -05:00
Dennis Boone
aa8095217f Merge pull request #5 from kej715/master
Add support for RJE MASTER mode in MDLC/HSSMLC controller, and use TRACE system instead of separate debug tracing.
2020-08-07 10:19:32 -04:00
Kevin Jordan
89043d09a4 Add support for RJE MASTER mode in MDLC/HSSMLC controller, and use
TRACE macro in the controller implementation.
2020-08-06 23:43:50 -04:00
Dennis Boone
e61857e333 Man page enhancements
Credit Kevin Jordan for sync serial support.

Add smlc.cfg info.

Improved explanation for instruction count and octal segno tracing.
2020-06-23 17:53:01 -04:00
Dennis Boone
4771f09e1e Minor tracing enhancements
Deconflict some values of instruction count with some of the
other tracing options by making it require a leading # before
the integer count.

Add/fix support for tracing execution within a designated segno.

Announce to the trace file that tracing is initialized.
2020-06-23 17:35:53 -04:00
Dennis Boone
6bf6e2ea48 Nanosecond log resolution for SMLC debug log
Using clock_gettime(), fetch the realtime clock, which has as much as
nanosecond resolution.  (In reality, it will likely ben more like
microseconds, though it returns the value in nanoseconds.) Use the
nanosecond value in SMLC log entries.  On modern systems and over
ethernet links, second resolution is probably fairly coarse for trying
to debug RJE problems.
2020-06-23 17:15:35 -04:00
Dennis Boone
edf7129651 Merge remote-tracking branch 'refs/remotes/origin/master' 2020-06-22 23:58:37 -04:00
Dennis Boone
543aa3f963 Fix link fail on x64-64
Weird gcc behavior.  Code snippet:

   uint16_t data;
   char ch;
   ...
   i = (data >> 8) & 0xff;
   ch = data & 0xff;
   ...
   fprintf(smlclog, "%s OTA '01%02o line '%02o set special character %d <%02x>\n", smlctimestamp, device, dc[dx].lineno, i, ch);

Output on x86-64 before this change:

    17:13:51 OTA '0150 line '02 set special character 3 <ffffffff>

Output on armhf or on x86-64 after this change:

    19:05:00.130466808 OTA '0150 line '02 set special character 3 <ff>

WTH?  Masking an unsigned with an appropriately sized mask produces a
sign extension?
2020-06-22 23:54:22 -04:00
Dennis Boone
7d7504a02e Clock resolution sniffer
The cmraw tool shows the approximate minimum time a program could
nanosleep, which tends to be quite a bit bigger than the smallest
value one could pass to nanosleep (one ns).  For example, on my
i7-3770 running linux, the results tend to be between 90 and 120 ns.
2020-06-11 13:22:48 -04:00
Dennis Boone
43d2d863d7 Replace tabs with spaces
Mixed tabs/spaces gets hairy.  I've expanded the tabs on the basis
of 8-position tabstops.
2020-05-30 01:42:39 -04:00
Dennis Boone
80c1a57895 Merge pull request #4 from kej715/master
MDLC/HSSMLC controller emulation to support Bisync and HASP for RJE
2020-05-30 00:17:58 -04:00
Kevin Jordan
d566f42ea6 Eliminate compiler warnings. 2020-05-29 22:46:09 -04:00
Kevin Jordan
af1718f699 Merge branch 'master' of https://github.com/kej715/p50em 2020-05-29 22:38:06 -04:00
Kevin Jordan
91bddd02c3 Add emulation of MDLC/HSSMLC controller to support Bisync protocol and enable a Prime
system to operate as a HASP station in an RJE environment. This implementation is
compatible with Bisync/HASP emulation in the Hercules IBM mainframe emulator and the
DtCyber CDC mainframe emulator.
2020-05-29 12:53:58 -04:00
Dennis Boone
4def8fe397 Support for booting DOS pre-Rev20
PRIMOS2 was built to be relocated after being loaded by BOOT.
The build process rewrote the RVEC in the save file.  The SA was anded
with :160000; the result was subtracted from SA and EA in the RVEC,
and stored into RA in the RVEC.  The BOOT program knew to add the RA
value during the load process.

This change causes the emulator to recognize such an RVEC when booting
an R-mode executable from unix disk, and to adjust the RVEC before
actually loading the program.  This fixes failure to boot *DOS64 from
19.2.9, for example.

The code only makes this adjustment if RA is non-zero, and RP is not
between SA and EA.
2020-05-27 19:06:55 -04:00
Jim Wilcoxson
43bbf3cd8f TCP_KEEPALIVE timer not supported on OSX 2020-05-27 18:49:35 -04:00
18 changed files with 3880 additions and 2330 deletions

15
.editorconfig Normal file
View 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
View 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
View 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
View 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

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
*.log
*.swp
tags
cmraw
cscope.*
em
emlink

View File

@@ -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

1334
devamlc.h

File diff suppressed because it is too large Load Diff

216
devpnc.h
View File

@@ -77,7 +77,7 @@
1: "Type" word.
Bit 1 set = odd number of bytes (if set, last word is only 1 byte)
Bit 7 set = normal data messages (otherwise, a timer message)
Bit 16 set = broadcast timer message
Bit 16 set = broadcast timer message
NOTE: at the hardware level, there are many other fields associated
with a ring packet on the wire, for example, a CRC, ack byte, etc.
@@ -121,15 +121,15 @@
7: data 2
PNC diagnostic register:
NORXTX EQU '100000 DISABLE TX AND RX
TXDATER EQU '040000 FORCE RX CRC ERROR
TXACKER EQU '020000 FORCE TX ACK ERROR
RXACKER EQU '010000 FORCE RX ACK BYTE ERROR
CABLE EQU '000001 LOOPBACK OVER CABLE
ANALOG EQU '000002 LOOPBACK THRU ANALOG DEVICES
SINGSTEP EQU '000004 LOOPBACK THRU SHIFT REG
RETRY EQU '000000 ALLOW HARDWR RETRY
NORETRY EQU '000010 NO HARDWR RETRY
NORXTX EQU '100000 DISABLE TX AND RX
TXDATER EQU '040000 FORCE RX CRC ERROR
TXACKER EQU '020000 FORCE TX ACK ERROR
RXACKER EQU '010000 FORCE RX ACK BYTE ERROR
CABLE EQU '000001 LOOPBACK OVER CABLE
ANALOG EQU '000002 LOOPBACK THRU ANALOG DEVICES
SINGSTEP EQU '000004 LOOPBACK THRU SHIFT REG
RETRY EQU '000000 ALLOW HARDWR RETRY
NORETRY EQU '000010 NO HARDWR RETRY
Primos PNC usage:
@@ -439,7 +439,7 @@ void pncaccept(time_t timenow) {
fd = accept(pncfd, (struct sockaddr *)&addr, &addrlen);
if (fd == -1) {
if (errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN)
perror("accept error for PNC");
perror("accept error for PNC");
return;
}
if (!(pncstat & PNCNSCONNECTED)) {
@@ -731,7 +731,7 @@ unsigned short pncxmit() {
if (xmit.toid == 255) {
for (nodeid=1; nodeid<=MAXNODEID; nodeid++)
if (ni[nodeid].cstate != PNCCSNONE)
xmitstat |= pncxmit1(nodeid);
xmitstat |= pncxmit1(nodeid);
} else {
xmitstat |= pncxmit1(xmit.toid);
}
@@ -764,7 +764,7 @@ void pncrecv() {
if (fd != -1)
FD_SET(fd, &fds);
if (fd > n)
n = fd;
n = fd;
}
n = select(n+1, &fds, NULL, NULL, &timeout);
if (n == -1) {
@@ -784,7 +784,7 @@ void pncrecv() {
fd = ni[nodeid].fd;
if (fd >= 0 && FD_ISSET(fd, &fds))
if (pncrecv1(nodeid))
break;
break;
} while (nodeid != prevnode); /* went round once? */
prevnode = nodeid;
}
@@ -853,7 +853,7 @@ int pncread (int nodeid, int nbytes) {
if (n == -1) {
if (errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN) {
if (errno != EPIPE)
fprintf(stderr, "error reading %d bytes from node %d: %s\n", nbytes, nodeid, strerror(errno));
fprintf(stderr, "error reading %d bytes from node %d: %s\n", nbytes, nodeid, strerror(errno));
pncdisc(nodeid, "error reading packet");
}
n = 0;
@@ -925,92 +925,92 @@ int devpnc (int class, int func, int device) {
where:
nodeid = node's id (1-247) on my ring
host = the remote emulator's TCP/IP address or name
port = the remote emulator's TCP/IP PNC port
NOTE: host:port may be - for incoming-only nodes
uid = 16 byte password, no spaces
NOTE: use od -h /dev/urandom|head to create a uid
port = the remote emulator's TCP/IP PNC port
NOTE: host:port may be - for incoming-only nodes
uid = 16 byte password, no spaces
NOTE: use od -h /dev/urandom|head to create a uid
*/
linenum = 0;
if ((ringfile=fopen("ring.cfg", "r")) != NULL) {
while (fgets(buf, sizeof(buf), ringfile) != NULL) {
len = strlen(buf);
linenum++;
if (buf[len-1] != '\n') {
fprintf(stderr,"Line %d of ring.cfg ignored: line too long, can't parse file\n", linenum);
return -1;
}
buf[len-1] = 0;
if (strcmp(buf,"") == 0 || buf[0] == ';' || buf[0] == '#')
continue;
len = strlen(buf);
linenum++;
if (buf[len-1] != '\n') {
fprintf(stderr,"Line %d of ring.cfg ignored: line too long, can't parse file\n", linenum);
return -1;
}
buf[len-1] = 0;
if (strcmp(buf,"") == 0 || buf[0] == ';' || buf[0] == '#')
continue;
if ((p=strtok(buf, DELIM)) == NULL) {
fprintf(stderr,"Line %d of ring.cfg ignored: node id missing\n", linenum);
continue;
}
tempid = atoi(p);
if (tempid < 1 || tempid > MAXNODEID) {
fprintf(stderr,"Line %d of ring.cfg ignored: node id is out of range 1-%d\n", linenum, MAXNODEID);
continue;
}
if (ni[tempid].cstate != PNCCSNONE) {
fprintf(stderr,"Line %d of ring.cfg ignored: node id occurs more than once\n", linenum);
continue;
}
if ((p=strtok(buf, DELIM)) == NULL) {
fprintf(stderr,"Line %d of ring.cfg ignored: node id missing\n", linenum);
continue;
}
tempid = atoi(p);
if (tempid < 1 || tempid > MAXNODEID) {
fprintf(stderr,"Line %d of ring.cfg ignored: node id is out of range 1-%d\n", linenum, MAXNODEID);
continue;
}
if (ni[tempid].cstate != PNCCSNONE) {
fprintf(stderr,"Line %d of ring.cfg ignored: node id occurs more than once\n", linenum);
continue;
}
if ((p=strtok(NULL, DELIM)) == NULL) {
fprintf(stderr,"Line %d of ring.cfg ignored: host address missing\n", linenum);
continue;
}
if (strlen(p) > MAXHOSTLEN) {
fprintf(stderr,"Line %d of ring.cfg ignored: IP address too long\n", linenum);
continue;
}
strncpy(temphost, p, MAXHOSTLEN);
if ((p=strtok(NULL, DELIM)) == NULL) {
fprintf(stderr,"Line %d of ring.cfg ignored: host address missing\n", linenum);
continue;
}
if (strlen(p) > MAXHOSTLEN) {
fprintf(stderr,"Line %d of ring.cfg ignored: IP address too long\n", linenum);
continue;
}
strncpy(temphost, p, MAXHOSTLEN);
if ((p=strtok(NULL, DELIM)) == NULL) {
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password missing\n", linenum);
continue;
}
if (strlen(p) > MAXUIDLEN) {
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password too long\n", linenum);
continue;
}
bzero(ni[tempid].uid, sizeof(ni[tempid].uid));
for (i=0; i<=MAXNODEID; i++)
if (strcmp(p, ni[i].uid) == 0) {
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password is not unique\n", linenum);
break;
}
if ((p=strtok(NULL, DELIM)) == NULL) {
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password missing\n", linenum);
continue;
}
if (strlen(p) > MAXUIDLEN) {
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password too long\n", linenum);
continue;
}
bzero(ni[tempid].uid, sizeof(ni[tempid].uid));
for (i=0; i<=MAXNODEID; i++)
if (strcmp(p, ni[i].uid) == 0) {
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password is not unique\n", linenum);
break;
}
if (i <= MAXNODEID)
continue;
strncpy(ni[tempid].uid, p, MAXUIDLEN);
continue;
strncpy(ni[tempid].uid, p, MAXUIDLEN);
/* parse the port number from the IP address */
/* parse the port number from the IP address */
tempport = 0;
if (strcmp(temphost, "-") != 0) {
if ((p=strtok(temphost, PDELIM)) != NULL) {
strncpy(ni[tempid].host, p, MAXHOSTLEN);
if ((p=strtok(NULL, PDELIM)) != NULL) {
tempport = atoi(p);
if (tempport < 1 || tempport > 65000)
fprintf(stderr,"Line %d of ring.cfg ignored: port number out of range 1-65000\n", linenum);
}
}
if (tempport <= 0) {
fprintf(stderr, "Line %d of ring.cfg ignored: can't parse port number from %s\n", linenum, temphost);
continue;
}
}
ni[tempid].cstate = PNCCSDISC;
ni[tempid].port = tempport;
TRACE(T_RIO, "Line %d: id=%d, host=\"%s\", port=%d, uid=%s\n", linenum, tempid, temphost, tempport, ni[tempid].uid);
configured = 1;
tempport = 0;
if (strcmp(temphost, "-") != 0) {
if ((p=strtok(temphost, PDELIM)) != NULL) {
strncpy(ni[tempid].host, p, MAXHOSTLEN);
if ((p=strtok(NULL, PDELIM)) != NULL) {
tempport = atoi(p);
if (tempport < 1 || tempport > 65000)
fprintf(stderr,"Line %d of ring.cfg ignored: port number out of range 1-65000\n", linenum);
}
}
if (tempport <= 0) {
fprintf(stderr, "Line %d of ring.cfg ignored: can't parse port number from %s\n", linenum, temphost);
continue;
}
}
ni[tempid].cstate = PNCCSDISC;
ni[tempid].port = tempport;
TRACE(T_RIO, "Line %d: id=%d, host=\"%s\", port=%d, uid=%s\n", linenum, tempid, temphost, tempport, ni[tempid].uid);
configured = 1;
}
if (!feof(ringfile)) {
perror(" error reading ring.cfg");
fatal(NULL);
perror(" error reading ring.cfg");
fatal(NULL);
}
fclose(ringfile);
} else
@@ -1087,7 +1087,7 @@ int devpnc (int class, int func, int device) {
if (func == 00) { /* OCP '0007 - disconnect */
TRACE(T_INST|T_RIO, " OCP '%02o%02o - disconnect\n", func, device);
for (i=0; i<=MAXNODEID; i++)
pncdisc(i, "ring disconnect");
pncdisc(i, "ring disconnect");
rcv.state = PNCBSIDLE;
rcvstat = PNCRSBUSY;
xmitstat = PNCXSBUSY;
@@ -1183,12 +1183,12 @@ int devpnc (int class, int func, int device) {
IOSKIP;
/* these next two are mostly bogus: prmnt1 T&M wants them this
way because it puts the PNC in diagnostic mode, disables
transmit and receive, then does transmit and receive
operations to see how the DMA registers are affected. I
couldn't get very far with this T&M (couldn't complete test
1) because it is so specific to the exact states the PNC
hardware moves through. */
way because it puts the PNC in diagnostic mode, disables
transmit and receive, then does transmit and receive
operations to see how the DMA registers are affected. I
couldn't get very far with this T&M (couldn't complete test
1) because it is so specific to the exact states the PNC
hardware moves through. */
} else if (func == 014) { /* read recv DMX channel */
TRACE(T_INST|T_RIO, " INA '%02o%02o - get recv DMX chan '%o 0x%04x\n", func, device, rcv.dmachan, rcv.dmachan);
@@ -1228,11 +1228,11 @@ int devpnc (int class, int func, int device) {
} else if (func == 014) { /* initiate recv, dma chan in A */
if (!(pncstat & PNCNSCONNECTED)) {
break; /* yes, return and don't skip */
break; /* yes, return and don't skip */
}
if (rcvstat & PNCRSBUSY) { /* already busy? */
warn("pnc: recv when already busy ignored");
break; /* yes, return and don't skip */
warn("pnc: recv when already busy ignored");
break; /* yes, return and don't skip */
}
IOSKIP;
rcvstat = PNCRSBUSY; /* set receive busy */
@@ -1241,11 +1241,11 @@ int devpnc (int class, int func, int device) {
} else if (func == 015) { /* initiate xmit, dma chan in A */
if (!(pncstat & PNCNSCONNECTED)) {
break; /* yes, return and don't skip */
break; /* yes, return and don't skip */
}
if (xmitstat & PNCXSBUSY) { /* already busy? */
warn("pnc: xmit when already busy ignored");
break; /* yes, return and don't skip */
warn("pnc: xmit when already busy ignored");
break; /* yes, return and don't skip */
}
IOSKIP;
pncxmit();
@@ -1259,12 +1259,12 @@ int devpnc (int class, int func, int device) {
} else if (func == 017) { /* set my node ID */
myid = getcrs16(A) & 0xFF;
if (myid > MAXNODEID) {
printf("em: my nodeid %d > max nodeid %d; check Primenet config\n", myid, MAXNODEID);
myid = 0;
printf("em: my nodeid %d > max nodeid %d; check Primenet config\n", myid, MAXNODEID);
myid = 0;
}
if (myid != 0 && ni[myid].cstate == PNCCSNONE) {
printf("em: my nodeid %d not in ring.cfg; PNC disabled\n", myid);
myid = 0;
printf("em: my nodeid %d not in ring.cfg; PNC disabled\n", myid);
myid = 0;
}
pncstat = (pncstat & 0xFF00) | myid;
ni[myid].cstate = PNCCSAUTH;
@@ -1303,10 +1303,10 @@ rcvexit:
intrexit:
if (enabled && ((pncstat & 0xC000) | intstat) != intstat) {
if (gv.intvec == -1) {
gv.intvec = pncvec;
intstat |= (pncstat & 0xC000);
gv.intvec = pncvec;
intstat |= (pncstat & 0xC000);
} else
devpoll[device] = 100;
devpoll[device] = 100;
}
break;

1292
devsmlc.h Normal file

File diff suppressed because it is too large Load Diff

28
ea32i.h
View File

@@ -26,33 +26,33 @@ static inline ea_t ea32i (ea_t earp, unsigned short inst, unsigned int *immu32,
d = iget16(RP);
RPL++;
if (sr == 0) /* imm type 1 */
*immu32 = d << 16;
*immu32 = d << 16;
else /* imm type 2 */
*(int *)immu32 = *(short *)&d;
*(int *)immu32 = *(short *)&d;
return IMM_EA;
case 2:
switch (sr) {
case 0: /* imm type 3 */
d = iget16(RP);
INCRP;
*immu64 = (((long long)(d & 0xFF00)) << 48) | (d & 0xFF);
return IMM_EA;
d = iget16(RP);
INCRP;
*immu64 = (((long long)(d & 0xFF00)) << 48) | (d & 0xFF);
return IMM_EA;
case 1: /* FAC0 source */
*immu64 = getgr64(FAC0);
return IMM_EA;
*immu64 = getgr64(FAC0);
return IMM_EA;
case 3: /* FAC1 source */
*immu64 = getgr64(FAC1);
return IMM_EA;
*immu64 = getgr64(FAC1);
return IMM_EA;
case 2:
case 4:
case 5:
case 6:
case 7:
fault(UIIFAULT, RPL, RP);
fatal("ea32i: return from UII fault!");
fault(UIIFAULT, RPL, RP);
fatal("ea32i: return from UII fault!");
default:
fatal("ea32i: sr < 0 or > 7?");
fatal("ea32i: sr < 0 or > 7?");
}
fatal("ea32i: case tm=0 br=2 fall-through");
@@ -62,7 +62,7 @@ static inline ea_t ea32i (ea_t earp, unsigned short inst, unsigned int *immu32,
ea = (getgr32(sr) & 0xFFFF0000) | ((getgr32(sr) + d) & 0xFFFF);
TRACE(T_EAI, " GRR, d=%x, [sr]=%o/%o, ea=%o/%o\n", d, getgr32(sr)>>16, getgr32(sr)&0xFFFF, ea>>16, ea&0xFFFF);
if (ea & 0x80000000)
fault(POINTERFAULT, ea>>16, ea);
fault(POINTERFAULT, ea>>16, ea);
return ea | ring;
default:

32
ea64v.h
View File

@@ -55,18 +55,18 @@ static inline ea_t ea64v (unsigned short inst, ea_t earp) {
if (xok)
if (ixy == 2 || ixy == 6)
ea_w += getcrs16(X);
ea_w += getcrs16(X);
else if (ixy == 1 || ixy == 4)
ea_w += getcrs16(Y);
ea_w += getcrs16(Y);
#if 0
/* if this is a PB% address, use RPBR instead if it's in range
NOTE: this has been disabled, because gcov showed it only
occurred 0.5% of the time */
NOTE: this has been disabled, because gcov showed it only
occurred 0.5% of the time */
if (br == 0 && ((((ea_s & 0x8FFF) << 16) | (ea_w & 0xFC00)) == gv.brp[RPBR].vpn))
eap = &gv.brp[RPBR];
eap = &gv.brp[RPBR];
#endif
if (ixy >= 3) {
@@ -74,26 +74,26 @@ static inline ea_t ea64v (unsigned short inst, ea_t earp) {
TRACE(T_EAV, " Long indirect, ea=%o/%o, ea_s=%o, ea_w=%o\n", ea>>16, ea&0xFFFF, ea_s, ea_w);
m = get16(ea);
if (m & 0x8000)
fault(POINTERFAULT, m, ea);
fault(POINTERFAULT, m, ea);
ea_s = m | (ea_s & RINGMASK16);
ea_w = get16(INCVA(ea,1));
TRACE(T_EAV, " After indirect, ea_s=%o, ea_w=%o\n", ea_s, ea_w);
/* when passing stack variables, callee references will be
SB%+20,*, which may still be in the same page. Don't switch to
UNBR if the new ea is still in the current page */
SB%+20,*, which may still be in the same page. Don't switch to
UNBR if the new ea is still in the current page */
if ((((ea_s & 0x8FFF) << 16) | (ea_w & 0xFC00)) != (eap->vpn & 0x0FFFFFFF))
eap = &gv.brp[UNBR];
eap = &gv.brp[UNBR];
if (xok)
if (ixy == 7) {
TRACE(T_EAV, " Postindex, old ea_w=%o, X='%o/%d\n", ea_w, getcrs16(X), getcrs16s(X));
ea_w += getcrs16(X);
} else if (ixy == 5) {
TRACE(T_EAV, " Postindex, old ea_w=%o, Y='%o/%d\n", ea_w, getcrs16(Y), getcrs16s(Y));
ea_w += getcrs16(Y);
}
if (ixy == 7) {
TRACE(T_EAV, " Postindex, old ea_w=%o, X='%o/%d\n", ea_w, getcrs16(X), getcrs16s(X));
ea_w += getcrs16(X);
} else if (ixy == 5) {
TRACE(T_EAV, " Postindex, old ea_w=%o, Y='%o/%d\n", ea_w, getcrs16(Y), getcrs16s(Y));
ea_w += getcrs16(Y);
}
}
return MAKEVA(ea_s, ea_w);
}

33
em.1
View File

@@ -2,7 +2,7 @@
.\" em.1, Boone, 03/13/20
.\" Man page for Jim Wilcoxson's Prime 50-Series emulator
.\" ---------------------------------------------------------------------------
.TH em 1 "2020-03-14" "Jim Wilcoxson" "50-Series Emulator"
.TH em 1 "2020-06-23" "Jim Wilcoxson" "50-Series Emulator"
.\" ---------------------------------------------------------------------------
.SH NAME
em \- Emulator for Prime 50-Series systems
@@ -35,6 +35,8 @@ a tape controller, 4 drives, using the .TAP format
.IP \(bu
a PNC controller emulating RingNet over TCP/IP
.IP \(bu
two sync serial controllers supporting up to 8 lines
.IP \(bu
a bypass for Primos system serial number checks
.IP \(bu
Unix utilities to read/write physical tapes & Magsav tapes
@@ -143,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
@@ -163,6 +174,18 @@ Example:
8 192.168.10.4:9000 # Outbound socket connection e.g. for spooler
.EE
.TP
smlc.cfg
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 # 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
All console output is also written to this file. It is overwritten
at each invocation. Created by
@@ -274,9 +297,12 @@ 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
#instruction count|Begin after specified number of instructions
|(the leading # is literal)
octal segno|Execution in the given segment number
|(may interact poorly with "off")
process number|Execution of this user number
.TE
.\" ---------------------------------------------------------------------------
@@ -360,7 +386,8 @@ CMD,1/3/5+1,Cartridge Module 32/64/96 MB
.\" ---------------------------------------------------------------------------
.SH AUTHOR
.PP
This emulator was written by Jim Wilcoxson. Man page by Dennis Boone.
This emulator was written by Jim Wilcoxson. MDLC/HSSMLC support by
Kevin Jordan. Man page by Dennis Boone.
.\" ---------------------------------------------------------------------------
.SH SEE ALSO
This project is hosted at

1723
em.c

File diff suppressed because it is too large Load Diff

1290
emdev.h

File diff suppressed because it is too large Load Diff

40
fp.h
View File

@@ -70,7 +70,7 @@ int prieee8(unsigned long long dp, double *d) {
if (frac64 == 0x8000000000000000LL) {
exp32 += (1023-128);
if (exp32 < 0 || exp32 > 0x7fe)
return 0;
return 0;
frac64 |= ((long long)exp32 << 52);
*d = *(double *)&frac64;
return 1;
@@ -142,11 +142,11 @@ retry:
okay = 0;
if (frac64 == 0)
if (neg) {
printf("em: +infinity in ieeepr8\n");
d = DBL_MAX;
printf("em: +infinity in ieeepr8\n");
d = DBL_MAX;
} else {
printf("em: -infinity in ieeepr8\n");
d = DBL_MIN;
printf("em: -infinity in ieeepr8\n");
d = DBL_MIN;
}
else {
printf("em: NaN in ieeepr8\n");
@@ -267,8 +267,8 @@ unsigned long long dfcm (unsigned long long dp, int *oflow) {
} else {
frac64 = -frac64; /* complement fraction */
while ((frac64 ^ (frac64 << 1)) >= 0) {
frac64 = frac64 << 1; /* normalize */
exp32--;
frac64 = frac64 << 1; /* normalize */
exp32--;
}
}
if (exp32 > 32767 || exp32 < -32768)
@@ -322,10 +322,10 @@ unsigned long long frn(unsigned long long dp, int *oflow) {
if (doround1 || doround2) {
frac64 &= 0xFFFFFF0000000000LL;
if (frac64 != 0x7FFFFF0000000000LL)
frac64 += 0x10000000000LL;
frac64 += 0x10000000000LL;
else {
frac64 = 0x4000000000000000LL;
exp32++;
frac64 = 0x4000000000000000LL;
exp32++;
}
frac64 |= (exp32 & 0xFFFF);
frac64 = norm(frac64, oflow);
@@ -359,13 +359,13 @@ int fcs (unsigned long long fac, int fop) {
if ((templ & 0x80000000) == (fop & 0x80000000)) { /* compare signs */
if (facexp == fopexp) /* compare exponents */
if (templ == fop) { /* compare fractions */
SETEQ;
return 1;
SETEQ;
return 1;
} else if (templ < fop) { /* compare fractions */
SETLT; /* FAC < operand */
return 2;
SETLT; /* FAC < operand */
return 2;
} else
return 0; /* FAC > operand */
return 0; /* FAC > operand */
else if (facexp < fopexp) { /* compare exponents */
SETLT; /* FAC < operand */
return 2;
@@ -410,13 +410,13 @@ int dfcs (unsigned long long fac, long long fop) {
if ((templl & 0x8000000000000000LL) == (fop & 0x8000000000000000LL)) { /* compare signs */
if (facexp == fopexp) /* compare exponents */
if (templl == fop) { /* compare fractions */
SETEQ;
return 1;
SETEQ;
return 1;
} else if (templl < fop) { /* compare fractions */
SETLT; /* FAC < operand */
return 2;
SETLT; /* FAC < operand */
return 2;
} else
return 0; /* FAC > operand */
return 0; /* FAC > operand */
else if (facexp < fopexp) { /* compare exponents */
SETLT; /* FAC < operand */
return 2;

View File

@@ -7,7 +7,7 @@ all_deps = makefile
em_objs = em.o em
em_deps = \
em.c regs.h emdev.h ea64v.h ea32i.h fp.h dispatch.h geom.h \
devpnc.h devamlc.h swap.h
devpnc.h devamlc.h devsmlc.h swap.h
CFLAGS =
# Uncomment for building on SmartOS/Solaris:

96
regs.h
View File

@@ -167,51 +167,51 @@ static struct {
/* this is the number of user register sets for this cpuid */
static short regsets[] = { \
2, /* 00 P400 */
2, /* 01 P400 (> REV A U-CODE) */
2, /* 02 RESERVED */
2, /* 03 P350 */
2, /* 04 P450/P550 */
2, /* 05 P750 */
2, /* 06 P650 */
2, /* 07 P150/P250 */
2, /* 08 P850 */
2, /* 09 MOLE/550 */
2, /* 10 MOLE/650 */
2, /* 11 P2250 */
2, /* 12 P750Y */
2, /* 13 P550Y */
2, /* 14 P850Y */
4, /* 15 P9950 */
8, /* 16 P9650 */
8, /* 17 P2550 */
4, /* 18 P9955 */
4, /* 19 P9750 */
2, /* 20 TBD */
8, /* 21 P2350 */
8, /* 22 P2655 */
8, /* 23 P9655 */
4, /* 24 P9955-TIGGER */
8, /* 25 P2450 */
4, /* 26 P4050 */
4, /* 27 P4150 */
4, /* 28 P6350 */
4, /* 29 P6550 */
4, /* 30 P9955-II */
8, /* 31 P2755 */
8, /* 32 P2455 */
4, /* 33 P5310 */
4, /* 34 P9755 */
4, /* 35 P2850 */
4, /* 36 P2950 */
4, /* 37 P5330 */
4, /* 38 P4450 */
4, /* 39 P5370 */
4, /* 40 P6650 */
4, /* 41 P6450 */
4, /* 42 P6150 */
4, /* 43 P5320 */
4}; /* 44 P5340 */
2, /* 00 P400 */
2, /* 01 P400 (> REV A U-CODE) */
2, /* 02 RESERVED */
2, /* 03 P350 */
2, /* 04 P450/P550 */
2, /* 05 P750 */
2, /* 06 P650 */
2, /* 07 P150/P250 */
2, /* 08 P850 */
2, /* 09 MOLE/550 */
2, /* 10 MOLE/650 */
2, /* 11 P2250 */
2, /* 12 P750Y */
2, /* 13 P550Y */
2, /* 14 P850Y */
4, /* 15 P9950 */
8, /* 16 P9650 */
8, /* 17 P2550 */
4, /* 18 P9955 */
4, /* 19 P9750 */
2, /* 20 TBD */
8, /* 21 P2350 */
8, /* 22 P2655 */
8, /* 23 P9655 */
4, /* 24 P9955-TIGGER */
8, /* 25 P2450 */
4, /* 26 P4050 */
4, /* 27 P4150 */
4, /* 28 P6350 */
4, /* 29 P6550 */
4, /* 30 P9955-II */
8, /* 31 P2755 */
8, /* 32 P2455 */
4, /* 33 P5310 */
4, /* 34 P9755 */
4, /* 35 P2850 */
4, /* 36 P2950 */
4, /* 37 P5330 */
4, /* 38 P4450 */
4, /* 39 P5370 */
4, /* 40 P6650 */
4, /* 41 P6450 */
4, /* 42 P6150 */
4, /* 43 P5320 */
4}; /* 44 P5340 */
static union {
int rs[REGSETS][32];
@@ -330,7 +330,7 @@ static inline void putcrs32(int offset, uint32_t val) { \
/* get 64-bit signed at 16-bit offset */
//#define getcrs64s(offset) *(long long *)(crs+(offset))
static inline int64_t getcrs64s(int offset) { \
return (long long)swap64(*(long long *)(crs+(offset))); \
return (long long)swap64(*(long long *)(crs+(offset))); \
}
/* put 64-bit signed at 16-bit offset */
@@ -342,7 +342,7 @@ static inline void putcrs64s(int offset, int64_t val) { \
/* put 64-bit double at 16-bit offset (remove later) */
//#define putcrs64d(offset, val) *(double *)(crs+(offset)) = (val)
static inline void putcrs64d(int offset, double val) { \
*(unsigned long long *)(crs+offset) = swap64(*(uint64_t *)&val); \
*(unsigned long long *)(crs+offset) = swap64(*(uint64_t *)&val); \
}
/* get 16-bit unsigned at 16-bit absolute register file address */
@@ -446,7 +446,7 @@ static inline void putfr64(int offset, unsigned long long val) { \
For FP 0, offset=0; for FP 1, offset=2 */
//#define putfr64d(offset, val) *(double *)(crsl+FAC0+offset) = (val)
static inline void putfr64d(int offset, double val) { \
*(unsigned long long *)(crsl+FAC0+offset) = swap64(*(uint64_t *)&val); \
*(unsigned long long *)(crsl+FAC0+offset) = swap64(*(uint64_t *)&val); \
}
#define PCBLEV 0

35
util/cmraw.c Normal file
View File

@@ -0,0 +1,35 @@
/* Show approximate minimum clock resolution
Derived from the example in the linux man page for clock_gettime() */
#define _XOPEN_SOURCE 600
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
static void displayClock(clockid_t clock, char *name)
{
struct timespec ts;
time_t oldsec;
long oldnsec;
clock_gettime(clock, &ts);
oldsec = ts.tv_sec;
oldnsec = ts.tv_nsec;
while (ts.tv_sec == oldsec && ts.tv_nsec == oldnsec)
{
if (clock_gettime(clock, &ts) == -1) {
perror("clock_gettime");
exit(EXIT_FAILURE);
}
}
printf("%-15s: %10ld sec %09ld nsec\n", name,
(long) ts.tv_sec - oldsec, ts.tv_nsec - oldnsec);
}
int main(int argc, char *argv[])
{
displayClock(CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW");
exit(0);
}