1
0
mirror of https://github.com/prirun/p50em.git synced 2026-03-23 16:42:17 +00:00

50 Commits

Author SHA1 Message Date
Dennis Boone
74aa7fe23e Trial command line option to suppress updating PRIMOS' DATNOW variable. 2025-09-29 20:38:30 -04:00
Dennis Boone
1819fed512 Error in link to install instructions
The link in README.md to install instructions was either old or
never quite right.  Point to DRB's overview document now, which
points (near) to the version specific ones.
2022-03-21 15:24:01 -04:00
Dennis Boone
64c5970e97 Added tracing for floating point operations. 2021-12-13 14:02:01 -05:00
Dennis Boone
c6c0344004 Additional #ifdef __APPLE__ sections removed
Some DTR handling was still inside of such #ifdefs, and thus
I was unable to make a modem work on a serial port.  I believe
this code is portable to OSX, Linux, FreeBSD, and Solaris.
2021-09-05 16:40:13 -04:00
Dennis Boone
0466b4b603 Emit mark parity space(s) in the "less than three" case, not space
parity ones.  Discovered by Daiyu.
2021-07-27 14:59:27 -04:00
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
Dennis Boone
9c6722ffc5 Set the keepalive idle time at accept time
Set the keepalive idle time per connection, at accept time,
using the setsockopt TCP_KEEPIDLE flag.  This seems to be
reasonably portable.
2020-05-17 00:35:04 -04:00
Dennis Boone
7e8e7236ec Turn on keepalive on accepted amlc telnet connections
On linux, keepalive defaults off.  The default timer on linux
is 7200 seconds.  Do we need to make a note in the docs about
setting /proc/sys/net/ipv4/tcp_keepalive_time?
2020-05-16 22:51:14 -04:00
Dennis Boone
07c7232878 Merge remote-tracking branch 'refs/remotes/origin/master' 2020-05-05 18:40:09 -04:00
Dennis Boone
8749def64f Changes to enable building on Solaris, FreeBSD
Solaris (SmartOS) build needs alternative solutions to two termios
things, plus makefile support for additional link libraries.  PNC
support is untested and is likely _very_ slow, since Solaris doesn't
have O_ASYNC.  The usual suggestion is to rewrite such code to use
poll().

Incidental: utilities makefile needed tabs to make `make` happy
on FreeBSD.  Which make?  Don't remember now.
2020-05-05 18:37:08 -04:00
Dennis Boone
633d61f2de Separate binaries package. 2020-05-05 18:29:03 -04:00
Jim Wilcoxson
ebf5511235 em.c: remove mips benchmark
Now that instpermsec is being adjusted every second instead of every
5 seconds, the initial value of instpermsec is not so critical.  This
benchmark gave wildly varying results on different system and compilers.
2020-05-01 16:26:19 -04:00
Jim Wilcoxson
280634b67e em.c: fix precendence bug caught by compiler
Only affects the display of keys (float exception enabled) on a fatal error.
2020-04-26 12:27:48 -04:00
Jim Wilcoxson
33f748f778 em.c: simpler iget16 and iget16t with same performance
Previously iget16 was used for all instruction fetches, with the
assumption that any could trap.  But actually, only the first word of
the instruction stream can trap in V mode, which is why these
instructions must be short.  Both words of a long R-mode instruction
can trap.

Tested change by booting R19 with and without -DFAST, all other revs
with -DFAST, and basic with trace on in R19 (this executes code from
the DFAC)
2020-04-20 16:14:03 +00:00
Jim Wilcoxson
6693ab36e2 Merge branch 'master' of https://github.com/prirun/p50em 2020-04-19 02:04:48 +00:00
Jim Wilcoxson
b3cada1dbf em.c: add a small benchmark loop to set the initial value of instpermsec
to a reasonable value.  This avoids clock anomolies during startup.
2020-04-19 01:14:15 +00:00
Dennis Boone
1d8476a807 Fix crash executing from registers during boot
In slow mode (compiled without -DFAST), Rev. 19 would crash during
boot.  On investigation, the code was branching to '4 after setting
up an instruction there.  However, instruction fetch found a '0
instead of the expected instruction.

Instructions might be fetched from registers via trap.  Fast iget16()
checks for fault.  Slow iget16() does not, and just calls get16() which
does not check.
2020-04-18 01:48:22 -04:00
Jim Wilcoxson
4a1bfefa4a Minimize clock inaccuracies during system boot
The initial estimate for instructions per millisec (instpermses) was
much too low for modern CPUs, and was also only updated every 5
seconds.  Combined, these were causing the clock to be erratic during
the first 5-15 seconds of system boot.

This was easily noticed by running the MIPS benchmark program right
after a system boot, where instead of delaying 5 seconds, it might
only delay 2 seconds, and then would report a bogus MIPS rating.
Waiting a minute and running it again would give an accurate rating.

Adjusting the instpermsec initial value from 2000 to 40000 and
IPMSTIME time from 5000 ms to 1000 ms (every second vs 5 seconds)
fixes the problem.
2020-04-18 03:11:56 +00:00
20 changed files with 4280 additions and 2649 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
@@ -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).
@@ -75,6 +78,19 @@ are available from Bitsavers:
* [Rev 22.1.4 repacked](https://yagi.h-net.org/m2214repack.tar.gz) [use this instead, resaved with Rev. 22 magsav]
* [Rev 19.?](http://bitsavers.org/bits/Prime/pps/03_log.tape_I=boot_II=iptpal.tap.gz) [a backup from an installed system]
## Pre-compiled binaries
We'd prefer that you build your own from the source tree, but if that's
not possible, a set of pre-compiled binaries is available. Included are:
* Linux i386
* Linux amd64
* Linux armhf (RasPi / BeagleBone)
* FreeBSD amd64
* Solaris amd64
[download](https://sysovl.info/pages/blobs/emulator/embinaries.20200504.tar.gz)
## Sample System Images
A set of sample system images derived from the public emulators can

1377
devamlc.h

File diff suppressed because it is too large Load Diff

220
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:
@@ -406,7 +406,11 @@ void pncinitfd(int fd) {
perror("unable to get ts flags for PNC");
fatal(NULL);
}
#ifdef __sun__
fdflags |= O_NONBLOCK;
#else
fdflags |= O_NONBLOCK+O_ASYNC;
#endif
if (fcntl(fd, F_SETFL, fdflags) == -1) {
perror("unable to set fdflags for PNC");
fatal(NULL);
@@ -435,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)) {
@@ -727,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);
}
@@ -760,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) {
@@ -780,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;
}
@@ -849,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;
@@ -921,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
@@ -1083,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;
@@ -1179,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);
@@ -1224,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 */
@@ -1237,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();
@@ -1255,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;
@@ -1299,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

2233
em.c

File diff suppressed because it is too large Load Diff

1326
emdev.h

File diff suppressed because it is too large Load Diff

124
fp.h
View File

@@ -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)
return 0;
{
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 */
@@ -142,11 +156,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");
@@ -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 */
@@ -267,8 +296,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)
@@ -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,23 +344,30 @@ 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)
frac64 += 0x10000000000LL;
frac64 += 0x10000000000LL;
else {
frac64 = 0x4000000000000000LL;
exp32++;
frac64 = 0x4000000000000000LL;
exp32++;
}
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 */
SETEQ;
return 1;
TRACE(T_FP, " fcs: frac cmp returning eq / skip 1\n");
SETEQ;
return 1;
} else if (templ < fop) { /* compare fractions */
SETLT; /* FAC < operand */
return 2;
} else
return 0; /* FAC > operand */
TRACE(T_FP, " fcs: frac cmp returning lt / skip 2\n");
SETLT; /* FAC < operand */
return 2;
} 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 */
SETEQ;
return 1;
TRACE(T_FP, " dfcs: frac cmp returning eq / skip 1\n");
SETEQ;
return 1;
} else if (templl < fop) { /* compare fractions */
SETLT; /* FAC < operand */
return 2;
} else
return 0; /* FAC > operand */
TRACE(T_FP, " dfcs: frac cmp returning lt / skip 2\n");
SETLT; /* FAC < operand */
return 2;
} 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 */
}
}

View File

@@ -7,25 +7,29 @@ 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:
# CFLAGS += -lsocket -lnsl
.PHONY: emwarn debug trace fixed
# normal
em: $(em_deps) $(all_deps)
$(CC) -DREV=\"${REV}\" -DNOTRACE -DFAST -O -Winline -Wno-return-type em.c -o em
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DNOTRACE -DFAST -O -Winline -Wno-return-type em.c -o em
# lots of compiler warnings
emwarn: $(em_deps) $(all_deps)
$(CC) -DREV=\"${REV}\" -DNOTRACE -DFAST -O -Wall -Wextra -pedantic -Wconversion em.c -o em
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DNOTRACE -DFAST -O -Wall -Wextra -pedantic -Wconversion em.c -o em
# gdb
debug: $(em_deps) $(all_deps)
$(CC) -DREV=\"${REV}\" -DNOTRACE -DFAST -g -O0 em.c -o em
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DNOTRACE -DFAST -g -O0 em.c -o em
# tracing
trace: $(em_deps) $(all_deps)
$(CC) -DREV=\"${REV}\" -DFAST -O em.c -o em
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DFAST -O em.c -o em
# the fixed clock rate build is useful for making problems reproduceable.
#
@@ -35,7 +39,7 @@ trace: $(em_deps) $(all_deps)
# fixed clock rate
fixed: $(em_deps) $(all_deps)
$(CC) -DREV=\"${REV}\" -DFIXEDCLOCK -DNOIDLE -DFAST -O em.c -o em
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DFIXEDCLOCK -DNOIDLE -DFAST -O em.c -o em
clean:
rm -f $(em_objs)

101
regs.h
View File

@@ -6,8 +6,6 @@
#define REGSETS 10
#define T_REGS 0x00100000
/* these are 16-bit absolute offsets into the register file */
#define PSWKEYS16 031*2
@@ -169,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];
@@ -294,7 +292,6 @@ static inline uint16_t getcrs16(int offset) { \
/* store 16-bit unsigned at 16-bit offset */
//#define putcrs16(offset, val) crs[(offset)] = (val)
static inline void putcrs16(int offset, uint16_t val) { \
TRACE(T_REGS, " putcrs16: offset %d val %06o\n", offset, val);
crs[(offset)] = swap16(val); \
}
@@ -315,7 +312,6 @@ static inline uint32_t getcrs32(int offset) { \
/* put 32-bit unsigned at 16-bit offset */
//#define putcrs32(offset, val) *(unsigned int *)(crs+(offset)) = (val)
static inline void putcrs32(int offset, uint32_t val) { \
TRACE(T_REGS, " putcrs32: offset %d val %012lo\n", offset, val);
*(unsigned int *)(crs+offset) = swap32(val); \
}
@@ -334,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 */
@@ -346,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 */
@@ -356,7 +352,6 @@ static inline uint16_t getar16(int offset) { \
/* put 16-bit unsigned at 16-bit absolute register file address */
static inline void putar16(int offset, uint16_t val) { \
TRACE(T_REGS, " putar16: offset %d val %06o\n", offset, val);
regs.u16[(offset)] = swap16(val); \
}
@@ -451,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);
}

View File

@@ -2,7 +2,7 @@ default: emlink intsize magrst magsav mtread mtwrite ptextu strip8 \
untap untap16 untap_vin utextp
# Unix version of Prime's magrst
magrst: magrst.c istext.c
magrst: magrst.c istext.c
# Unix version of Prime's magsav
magsav: magsav.c istext.c
magsav: magsav.c istext.c

View File

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