mirror of
https://github.com/prirun/p50em.git
synced 2026-03-24 08:59:37 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2458dd7c2e |
@@ -1,15 +0,0 @@
|
|||||||
# .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
26
.github/workflows/freebsdbuild.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
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
22
.github/workflows/linuxbuild.yml
vendored
@@ -1,22 +0,0 @@
|
|||||||
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
22
.github/workflows/macbuild.yml
vendored
@@ -1,22 +0,0 @@
|
|||||||
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
1
.gitignore
vendored
@@ -3,7 +3,6 @@
|
|||||||
*.log
|
*.log
|
||||||
*.swp
|
*.swp
|
||||||
tags
|
tags
|
||||||
cmraw
|
|
||||||
cscope.*
|
cscope.*
|
||||||
em
|
em
|
||||||
emlink
|
emlink
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -22,9 +22,6 @@ the host processor having a large set of general-purpose registers.
|
|||||||
Coming soon, we swear! There is a unix man page included in this
|
Coming soon, we swear! There is a unix man page included in this
|
||||||
repository.
|
repository.
|
||||||
|
|
||||||
Github discussions are now enabled for this repository, and can be
|
|
||||||
used to ask for help.
|
|
||||||
|
|
||||||
## Public Systems
|
## Public Systems
|
||||||
|
|
||||||
There are a set of emulators available for public use. These may be
|
There are a set of emulators available for public use. These may be
|
||||||
@@ -55,7 +52,7 @@ business unit ceased to exist. A reformatted copy is available
|
|||||||
A growing collection of Prime and related documentation is available
|
A growing collection of Prime and related documentation is available
|
||||||
at [sysovl.info](https://sysovl.info/reference_prime.html).
|
at [sysovl.info](https://sysovl.info/reference_prime.html).
|
||||||
A howto on installing PRIMOS in the emulator is
|
A howto on installing PRIMOS in the emulator is
|
||||||
[here](https://sysovl.info/reference_prime_drb_installoview.html).
|
[here](https://sysovl.info/reference_prime_drb_installing_primos.html).
|
||||||
Discussion of adapting these instructions to
|
Discussion of adapting these instructions to
|
||||||
22.1.4 has been occurring on the [cctalk mailing
|
22.1.4 has been occurring on the [cctalk mailing
|
||||||
list](http://classiccmp.org/pipermail/cctalk/2020-March/052126.html).
|
list](http://classiccmp.org/pipermail/cctalk/2020-March/052126.html).
|
||||||
@@ -78,19 +75,6 @@ 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 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]
|
* [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
|
## Sample System Images
|
||||||
|
|
||||||
A set of sample system images derived from the public emulators can
|
A set of sample system images derived from the public emulators can
|
||||||
|
|||||||
81
devamlc.h
81
devamlc.h
@@ -150,8 +150,6 @@ AMLC status word (from AMLCT5):
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <termio.h>
|
|
||||||
|
|
||||||
/* this macro closes an AMLC connection - used in several places
|
/* this macro closes an AMLC connection - used in several places
|
||||||
|
|
||||||
NOTE: don't print disconnect message on dedicated lines */
|
NOTE: don't print disconnect message on dedicated lines */
|
||||||
@@ -264,7 +262,6 @@ int devamlc (int class, int func, int device) {
|
|||||||
unsigned short ctinterrupt; /* 1 bit per line */
|
unsigned short ctinterrupt; /* 1 bit per line */
|
||||||
unsigned short dss; /* 1 bit per line */
|
unsigned short dss; /* 1 bit per line */
|
||||||
unsigned short connected; /* 1 bit per line */
|
unsigned short connected; /* 1 bit per line */
|
||||||
unsigned short dolineclear; /* 1 bit per line */
|
|
||||||
unsigned short serial; /* true if any CT_SERIAL lines */
|
unsigned short serial; /* true if any CT_SERIAL lines */
|
||||||
unsigned short dsstime; /* countdown to dss poll */
|
unsigned short dsstime; /* countdown to dss poll */
|
||||||
short fd[16]; /* Unix fd, 1 per line */
|
short fd[16]; /* Unix fd, 1 per line */
|
||||||
@@ -332,7 +329,6 @@ int devamlc (int class, int func, int device) {
|
|||||||
for (dx=0; dx<MAXBOARDS; dx++) {
|
for (dx=0; dx<MAXBOARDS; dx++) {
|
||||||
dc[dx].deviceid = 0;
|
dc[dx].deviceid = 0;
|
||||||
dc[dx].connected = 0;
|
dc[dx].connected = 0;
|
||||||
dc[dx].dolineclear = 0;
|
|
||||||
dc[dx].serial = 0;
|
dc[dx].serial = 0;
|
||||||
for (lx = 0; lx < 16; lx++) {
|
for (lx = 0; lx < 16; lx++) {
|
||||||
dc[dx].fd[lx] = -1;
|
dc[dx].fd[lx] = -1;
|
||||||
@@ -561,7 +557,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
if (dc[dx].serial) { /* any serial connections? */
|
if (dc[dx].serial) { /* any serial connections? */
|
||||||
if (--dc[dx].dsstime == 0) {
|
if (--dc[dx].dsstime == 0) {
|
||||||
dc[dx].dsstime = DSSCOUNTDOWN;
|
dc[dx].dsstime = DSSCOUNTDOWN;
|
||||||
/* #ifdef __APPLE__ */
|
#ifdef __APPLE__
|
||||||
for (lx = 0; lx < 16; lx++) { /* yes, poll them */
|
for (lx = 0; lx < 16; lx++) { /* yes, poll them */
|
||||||
if (dc[dx].ctype[lx] == CT_SERIAL) {
|
if (dc[dx].ctype[lx] == CT_SERIAL) {
|
||||||
int modemstate;
|
int modemstate;
|
||||||
@@ -577,7 +573,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* #endif */
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//printf("devamlc: dss for device '%o = 0x%x\n", device, dc[dx].dss);
|
//printf("devamlc: dss for device '%o = 0x%x\n", device, dc[dx].dss);
|
||||||
@@ -654,22 +650,9 @@ int devamlc (int class, int func, int device) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memset(&terminfo, 0, sizeof(terminfo));
|
memset(&terminfo, 0, sizeof(terminfo));
|
||||||
#ifdef __sun__
|
|
||||||
terminfo.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
|
||||||
terminfo.c_oflag &= ~OPOST;
|
|
||||||
terminfo.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
|
||||||
terminfo.c_cflag &= ~(CSIZE|PARENB);
|
|
||||||
terminfo.c_cflag |= CS8;
|
|
||||||
#else
|
|
||||||
cfmakeraw(&terminfo);
|
cfmakeraw(&terminfo);
|
||||||
#endif
|
|
||||||
baud = baudtable[(getcrs16(A) >> 6) & 7];
|
baud = baudtable[(getcrs16(A) >> 6) & 7];
|
||||||
#ifdef __sun__
|
|
||||||
if ((cfsetispeed(&terminfo, baud) == -1) ||
|
|
||||||
(cfsetospeed(&terminfo, baud) == -1))
|
|
||||||
#else
|
|
||||||
if (cfsetspeed(&terminfo, baud) == -1)
|
if (cfsetspeed(&terminfo, baud) == -1)
|
||||||
#endif
|
|
||||||
perror("em: unable to set AMLC line speed");
|
perror("em: unable to set AMLC line speed");
|
||||||
else
|
else
|
||||||
printf("em: AMLC line %d set to %d bps\n", dx*16 + lx, baud);
|
printf("em: AMLC line %d set to %d bps\n", dx*16 + lx, baud);
|
||||||
@@ -760,6 +743,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
|
|
||||||
/* set DTR high (02000) or low if it has changed */
|
/* set DTR high (02000) or low if it has changed */
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
if ((getcrs16(A) ^ dc[dx].lconf[lx]) & 02000) {
|
if ((getcrs16(A) ^ dc[dx].lconf[lx]) & 02000) {
|
||||||
int modemstate;
|
int modemstate;
|
||||||
//printf("devamlc: DTR state changed\n");
|
//printf("devamlc: DTR state changed\n");
|
||||||
@@ -772,6 +756,7 @@ int devamlc (int class, int func, int device) {
|
|||||||
}
|
}
|
||||||
ioctl(fd, TIOCMSET, &modemstate);
|
ioctl(fd, TIOCMSET, &modemstate);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,7 +872,6 @@ int devamlc (int class, int func, int device) {
|
|||||||
close(dc[i].fd[lx]);
|
close(dc[i].fd[lx]);
|
||||||
dc[i].dss |= BITMASK16(lx+1);
|
dc[i].dss |= BITMASK16(lx+1);
|
||||||
dc[i].connected |= BITMASK16(lx+1);
|
dc[i].connected |= BITMASK16(lx+1);
|
||||||
dc[i].dolineclear |= BITMASK16(lx+1);
|
|
||||||
dc[i].fd[lx] = fd;
|
dc[i].fd[lx] = fd;
|
||||||
dc[i].tstate[lx] = TS_DATA;
|
dc[i].tstate[lx] = TS_DATA;
|
||||||
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
|
//printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, dc[i].deviceid, lx);
|
||||||
@@ -914,16 +898,6 @@ int devamlc (int class, int func, int device) {
|
|||||||
optval = 1;
|
optval = 1;
|
||||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1)
|
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1)
|
||||||
perror("unable to set TCP_NODELAY");
|
perror("unable to set TCP_NODELAY");
|
||||||
#ifndef __APPLE__
|
|
||||||
/* Set 600 second keepalive idle time for this socket */
|
|
||||||
optval = 600;
|
|
||||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval)) == -1)
|
|
||||||
perror("unable to set TCP_KEEPIDLE");
|
|
||||||
#endif
|
|
||||||
/* ... and turn on keepalive */
|
|
||||||
optval = 1;
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1)
|
|
||||||
perror("unable to set SO_KEEPALIVE");
|
|
||||||
|
|
||||||
/* these Telnet commands put the connecting telnet client
|
/* these Telnet commands put the connecting telnet client
|
||||||
into character-at-a-time mode and binary mode. Since
|
into character-at-a-time mode and binary mode. Since
|
||||||
@@ -1143,53 +1117,6 @@ dorecv:
|
|||||||
if (dc[dx].deviceid == 0 || dc[dx].connected == 0 || dc[dx].eor)
|
if (dc[dx].deviceid == 0 || dc[dx].connected == 0 || dc[dx].eor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Inject xon / kill if dolineclear is true */
|
|
||||||
|
|
||||||
if (dolinecleararg)
|
|
||||||
for (lx = 0; lx < 16; lx++)
|
|
||||||
if (dc[dx].dolineclear & BITMASK16(lx+1))
|
|
||||||
{
|
|
||||||
unsigned char ch;
|
|
||||||
unsigned short utemp;
|
|
||||||
int dmcpair, lcount;
|
|
||||||
ea_t dmcea, dmcbufbegea, dmcbufendea;
|
|
||||||
unsigned short dmcnw;
|
|
||||||
|
|
||||||
if (dc[dx].bufnum)
|
|
||||||
dmcea = dc[dx].dmcchan + 2;
|
|
||||||
else
|
|
||||||
dmcea = dc[dx].dmcchan;
|
|
||||||
dmcpair = get32io(dmcea);
|
|
||||||
dmcbufbegea = dmcpair>>16;
|
|
||||||
dmcbufendea = dmcpair & 0xffff;
|
|
||||||
dmcnw = dmcbufendea - dmcbufbegea + 1;
|
|
||||||
|
|
||||||
if (dmcnw < 2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
utemp = lx<<12 | 0x0200 | 0221; /* dc1/xon */
|
|
||||||
put16io(utemp, dmcbufbegea);
|
|
||||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
|
||||||
|
|
||||||
ch = (unsigned char)get16(MAKEVA(014, 0705));
|
|
||||||
utemp = lx<<12 | 0x0200 | ch; /* kill */
|
|
||||||
put16io(utemp, dmcbufbegea);
|
|
||||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
|
||||||
|
|
||||||
dc[dx].recvlx = lx;
|
|
||||||
if (dmcbufbegea-1 > dmcbufendea)
|
|
||||||
fatal("AMLC tumble table overflowed?");
|
|
||||||
put16io(dmcbufbegea, dmcea);
|
|
||||||
if (dmcbufbegea > dmcbufendea) { /* end of range has occurred */
|
|
||||||
dc[dx].bufnum = 1-dc[dx].bufnum;
|
|
||||||
dc[dx].eor = 1;
|
|
||||||
neweor = 1;
|
|
||||||
anyeor = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dc[dx].dolineclear &= ~BITMASK16(lx+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* select to see which lines have data to be read */
|
/* select to see which lines have data to be read */
|
||||||
|
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
|
|||||||
4
devpnc.h
4
devpnc.h
@@ -406,11 +406,7 @@ void pncinitfd(int fd) {
|
|||||||
perror("unable to get ts flags for PNC");
|
perror("unable to get ts flags for PNC");
|
||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
}
|
}
|
||||||
#ifdef __sun__
|
|
||||||
fdflags |= O_NONBLOCK;
|
|
||||||
#else
|
|
||||||
fdflags |= O_NONBLOCK+O_ASYNC;
|
fdflags |= O_NONBLOCK+O_ASYNC;
|
||||||
#endif
|
|
||||||
if (fcntl(fd, F_SETFL, fdflags) == -1) {
|
if (fcntl(fd, F_SETFL, fdflags) == -1) {
|
||||||
perror("unable to set fdflags for PNC");
|
perror("unable to set fdflags for PNC");
|
||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
|
|||||||
33
em.1
33
em.1
@@ -2,7 +2,7 @@
|
|||||||
.\" em.1, Boone, 03/13/20
|
.\" em.1, Boone, 03/13/20
|
||||||
.\" Man page for Jim Wilcoxson's Prime 50-Series emulator
|
.\" Man page for Jim Wilcoxson's Prime 50-Series emulator
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.TH em 1 "2020-06-23" "Jim Wilcoxson" "50-Series Emulator"
|
.TH em 1 "2020-03-14" "Jim Wilcoxson" "50-Series Emulator"
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH NAME
|
.SH NAME
|
||||||
em \- Emulator for Prime 50-Series systems
|
em \- Emulator for Prime 50-Series systems
|
||||||
@@ -35,8 +35,6 @@ a tape controller, 4 drives, using the .TAP format
|
|||||||
.IP \(bu
|
.IP \(bu
|
||||||
a PNC controller emulating RingNet over TCP/IP
|
a PNC controller emulating RingNet over TCP/IP
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
two sync serial controllers supporting up to 8 lines
|
|
||||||
.IP \(bu
|
|
||||||
a bypass for Primos system serial number checks
|
a bypass for Primos system serial number checks
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
Unix utilities to read/write physical tapes & Magsav tapes
|
Unix utilities to read/write physical tapes & Magsav tapes
|
||||||
@@ -145,15 +143,6 @@ on the host. Multiple trace types may be listed, separated by
|
|||||||
spaces. Tracing may be initially turned off by including the
|
spaces. Tracing may be initially turned off by including the
|
||||||
.I off
|
.I off
|
||||||
trace type.
|
trace type.
|
||||||
.PP
|
|
||||||
\fB-dolineclear\fR
|
|
||||||
.IP
|
|
||||||
Inject an XON (DC1, 0221) character and a line kill character into the
|
|
||||||
input buffers each time an AMLC line receives an incoming connection.
|
|
||||||
The system's configured line kill character is fetched from the
|
|
||||||
DEFKIL field of FIGCOM, at address 14(0)/705. This behavior helps
|
|
||||||
counteract lines which have been blocked by internet vulnerability
|
|
||||||
scanners injecting non-telnet data streams.
|
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.TP
|
.TP
|
||||||
@@ -174,18 +163,6 @@ Example:
|
|||||||
8 192.168.10.4:9000 # Outbound socket connection e.g. for spooler
|
8 192.168.10.4:9000 # Outbound socket connection e.g. for spooler
|
||||||
.EE
|
.EE
|
||||||
.TP
|
.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
|
console.log
|
||||||
All console output is also written to this file. It is overwritten
|
All console output is also written to this file. It is overwritten
|
||||||
at each invocation. Created by
|
at each invocation. Created by
|
||||||
@@ -297,12 +274,9 @@ off|Start with tracing disabled
|
|||||||
all|Everything
|
all|Everything
|
||||||
flush|Flush trace file after each write
|
flush|Flush trace file after each write
|
||||||
tlb|STLB and IOTLB changes
|
tlb|STLB and IOTLB changes
|
||||||
smlc|MDLC/HSSMLC device I/O
|
|
||||||
OWNERL|Execution of this PCB
|
OWNERL|Execution of this PCB
|
||||||
#instruction count|Begin after specified number of instructions
|
instruction count|Begin after specified number of instructions
|
||||||
|(the leading # is literal)
|
|
||||||
octal segno|Execution in the given segment number
|
octal segno|Execution in the given segment number
|
||||||
|(may interact poorly with "off")
|
|
||||||
process number|Execution of this user number
|
process number|Execution of this user number
|
||||||
.TE
|
.TE
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
@@ -386,8 +360,7 @@ CMD,1/3/5+1,Cartridge Module 32/64/96 MB
|
|||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.PP
|
.PP
|
||||||
This emulator was written by Jim Wilcoxson. MDLC/HSSMLC support by
|
This emulator was written by Jim Wilcoxson. Man page by Dennis Boone.
|
||||||
Kevin Jordan. Man page by Dennis Boone.
|
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
This project is hosted at
|
This project is hosted at
|
||||||
|
|||||||
621
em.c
621
em.c
@@ -1,5 +1,5 @@
|
|||||||
/* Pr1me Computer emulator, Jim Wilcoxson (prirun@gmail.com), April 4, 2005
|
/* Pr1me Computer emulator, Jim Wilcoxson (prirun@gmail.com), April 4, 2005
|
||||||
Copyright (C) 2005-2021, Jim Wilcoxson. All Rights Reserved.
|
Copyright (C) 2005-2019, Jim Wilcoxson. All Rights Reserved.
|
||||||
|
|
||||||
Emulates a Prime Computer system by:
|
Emulates a Prime Computer system by:
|
||||||
- booting from a Prime disk image (normal usage)
|
- booting from a Prime disk image (normal usage)
|
||||||
@@ -132,6 +132,253 @@ gv.tracetriggered = 1; this simulates the Ctrl-t.
|
|||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
|
||||||
|
#define IOTLBENTS 64*4
|
||||||
|
#define STLBENTS 512
|
||||||
|
|
||||||
|
typedef unsigned int ea_t; /* effective address */
|
||||||
|
typedef unsigned int pa_t; /* physical address */
|
||||||
|
|
||||||
|
/* STLB cache structure is defined here; the actual stlb is in gv.
|
||||||
|
There are several different styles on Prime models. This is
|
||||||
|
modeled after the 6350 STLB, but is only 1-way associative.
|
||||||
|
The hit rate has been measured to be over 99.8% with a single
|
||||||
|
user.
|
||||||
|
|
||||||
|
Instead of using a valid/invalid bit, a segment number of 0xFFFF
|
||||||
|
(note that the fault, ring, and E bits are set) means "invalid",
|
||||||
|
since it won't match any 12-bit segment number. This eliminates
|
||||||
|
testing the valid bit in mapva.
|
||||||
|
|
||||||
|
As a speed-up, the unmodified bit is stored in access[2], where
|
||||||
|
Ring 2 access should be kept. This makes the structure exactly 16
|
||||||
|
bytes, so indexing into the table can use a left shift 4
|
||||||
|
instruction rather than a multiply by 20. It saves a multiply in
|
||||||
|
the fast path of a _very_ speed-critical routine (mapva).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STLB_UNMODIFIED_BIT 2 /* stored in access[2] */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int pmaddr; /* Prime phys addr of page table flag word */
|
||||||
|
unsigned int ppa; /* physical page address (PPN << 10) */
|
||||||
|
unsigned short procid; /* process id for segments >= '4000 */
|
||||||
|
short seg; /* segment number (0-0xFFF), 0xFFFF = invalid */
|
||||||
|
char access[4]; /* ring n access rights */
|
||||||
|
//char unmodified; /* 1 = page not modified, 0 = modified */
|
||||||
|
//char shared; /* 1 if page is shared and can't be cached */
|
||||||
|
//char valid; /* 1 if STLB entry is valid, zero otherwise */
|
||||||
|
#ifndef NOTRACE
|
||||||
|
unsigned int load_ic; /* instruction where STLB was loaded, (debug) */
|
||||||
|
#endif
|
||||||
|
} stlbe_t;
|
||||||
|
|
||||||
|
/* The IOTLB stores translations for each page of the I/O segments 0-3 */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int ppa; /* physical page address (PPN << 10) */
|
||||||
|
char valid; /* 1 if IOTLB entry is valid, zero otherwise */
|
||||||
|
} iotlbe_t;
|
||||||
|
|
||||||
|
/* the emulator uses a special, very small address translation cache
|
||||||
|
to hold the virtual page address and corresponding MEM[] pointer
|
||||||
|
for a few special pages:
|
||||||
|
|
||||||
|
- the 4 base registers (PBBR, SBBR, LBBR, XBBR)
|
||||||
|
- the current instruction page (RPBR)
|
||||||
|
- sector zero (S0BR) of the current procedure
|
||||||
|
- field address registers 0 and 1 (F0BR, F1BR)
|
||||||
|
- "unknown", used for indirect references (UNBR)
|
||||||
|
|
||||||
|
When an effective address is calculated, eap is set to point to one
|
||||||
|
of these cache entries. If the EA, which is a virtual address,
|
||||||
|
references the same page as the cache entry pointed to by eap, then
|
||||||
|
the mapva call can be bypassed and the physical memory address
|
||||||
|
calculated using the cache. If the cache can't be used, either
|
||||||
|
because the entry is invalid, points to a different virtual page,
|
||||||
|
or the access isn't allowed (only for writes), mapva is called to
|
||||||
|
do the mapping and (assuming it doesn't fault) the eap cache entry
|
||||||
|
is updated.
|
||||||
|
|
||||||
|
This special cache is invalidated when the STLB is changed, a ring
|
||||||
|
change occurs, on process exchange, and on LPSW. For reads, no
|
||||||
|
access checking is needed when the cache is used: the cache entry
|
||||||
|
is either valid, meaning that the program has at least read access
|
||||||
|
to the page, or the cache entry is invalid (special value of
|
||||||
|
0x000000FF, which is not a virtual page address - the right 10 bits
|
||||||
|
must be zero for the start of a page), in which case mapva is
|
||||||
|
called.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
IMPORTANT NOTE: bit 4 MUST BE CHECKED before all write references!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PBBR 0
|
||||||
|
#define SBBR 1
|
||||||
|
#define LBBR 2
|
||||||
|
#define XBBR 3
|
||||||
|
#define RPBR 4
|
||||||
|
#define S0BR 5
|
||||||
|
#define F0BR 6
|
||||||
|
#define F1BR 7
|
||||||
|
#define UNBR 8
|
||||||
|
#define BRP_SIZE 9
|
||||||
|
|
||||||
|
/* NOTE: vpn is a segment number/word offset Prime virtual address
|
||||||
|
corresponding to the physical page of memory in memp. The high-
|
||||||
|
order fault bit of vpn is never set. The ring and extension bits
|
||||||
|
are used to store the 3-bit access field from the STLB for the
|
||||||
|
current ring.
|
||||||
|
|
||||||
|
All brp entries are invalidated by PCL and PRTN when the ring
|
||||||
|
changes, ITLB, PTLB, and LIOT (STLB changes), when OWNERL changes
|
||||||
|
(process exchange), and on LPSW.
|
||||||
|
|
||||||
|
Storing the access bits in the vpn allows use of of the brp cache
|
||||||
|
for write accesses as well as read accesses. Only bit 4 (write
|
||||||
|
allowed) is used, but since a 3-bit value comes back from mapva,
|
||||||
|
it's easier just to put it all in vpn.
|
||||||
|
|
||||||
|
IMPORTANT NOTE: the "get" calls do not store the access field in
|
||||||
|
the brp cache entry; the first write to a page must clear the "page
|
||||||
|
unmodified" bit in the Primos page maps, and mapva is the only way
|
||||||
|
to do this. So the first "put" has to go through mapva. An
|
||||||
|
alternative would be to store the page map pointer in brp and use
|
||||||
|
bit 3 of vpn as a flag for whether the page map has to be modified,
|
||||||
|
but this is more work for probably little gain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned short *memp; /* MEM[] physical page address */
|
||||||
|
ea_t vpn; /* corresponding virtual page address */
|
||||||
|
} brp_t;
|
||||||
|
|
||||||
|
/* "gv" is a static structure used to hold "hot" global variables. These
|
||||||
|
are pointed to by a dedicated register, so that the usual PowerPC global
|
||||||
|
variable instructions aren't needed: these variables can be directly
|
||||||
|
referenced by instructions as long as the structure is < 16K bytes. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
int memlimit; /* user's desired memory limit (-mem) */
|
||||||
|
|
||||||
|
int intvec; /* currently raised interrupt (if >= zero) */
|
||||||
|
|
||||||
|
unsigned int instcount; /* global instruction count */
|
||||||
|
|
||||||
|
brp_t brp[BRP_SIZE]; /* PB, SB, LB, XB, RP, S0, F0, F1, UN */
|
||||||
|
|
||||||
|
unsigned short inhcount; /* number of instructions to stay inhibited */
|
||||||
|
|
||||||
|
unsigned int instpermsec; /* instructions executed per millisecond */
|
||||||
|
|
||||||
|
stlbe_t stlb[STLBENTS]; /* the STLB: Segmentation Translation Lookaside Buffer */
|
||||||
|
|
||||||
|
iotlbe_t iotlb[IOTLBENTS]; /* the IOTLB: I/O Translation Lookaside Buffer */
|
||||||
|
|
||||||
|
unsigned int prevpc; /* backed program counter */
|
||||||
|
|
||||||
|
unsigned short amask; /* address mask */
|
||||||
|
|
||||||
|
int pmap32bits; /* true if 32-bit page maps */
|
||||||
|
|
||||||
|
int pmap32mask; /* mask for 32-bit page maps */
|
||||||
|
|
||||||
|
int csoffset; /* concealed stack segment offset */
|
||||||
|
|
||||||
|
unsigned int livereglim; /* 010 if seg enabled, 040 if disabled */
|
||||||
|
|
||||||
|
int mapvacalls; /* # of mapva calls */
|
||||||
|
int mapvamisses; /* STLB misses */
|
||||||
|
int supercalls; /* brp supercache hits */
|
||||||
|
int supermisses; /* brp supercache misses */
|
||||||
|
|
||||||
|
void *disp_rmr[128]; /* R-mode memory ref dispatch table */
|
||||||
|
void *disp_vmr[128]; /* V-mode memory ref dispatch table */
|
||||||
|
|
||||||
|
#ifndef NOTRACE
|
||||||
|
|
||||||
|
/* traceflags is the variable used to test tracing of each instruction
|
||||||
|
traceuser is the user number to trace, 0 meaning any user
|
||||||
|
traceseg is the procedure segment number to trace, 0 meaning any
|
||||||
|
savetraceflags hold the real traceflags, while "traceflags" switches
|
||||||
|
on and off for each instruction
|
||||||
|
|
||||||
|
TRACEUSER is a macro that is true if the current user is being traced
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAXRPQ 8
|
||||||
|
|
||||||
|
FILE *tracefile; /* trace.log file */
|
||||||
|
int traceflags; /* each bit is a trace flag */
|
||||||
|
int savetraceflags;
|
||||||
|
unsigned short traceuser; /* OWNERL to trace */
|
||||||
|
short traceseg; /* RPH segment # to trace */
|
||||||
|
short numtraceprocs; /* # of procedures we're tracing */
|
||||||
|
unsigned int traceinstcount; /* only trace if instcount > this */
|
||||||
|
short tracetriggered; /* Ctrl-T on console toggles tracing */
|
||||||
|
short tracerpqx; /* rpq index to store next RP */
|
||||||
|
unsigned int tracerpq[MAXRPQ];/* last 16 locations executed */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} gv_t;
|
||||||
|
|
||||||
|
static gv_t gv;
|
||||||
|
|
||||||
|
/* trace flags to control aspects of emulator tracing:
|
||||||
|
|
||||||
|
T_EAR trace R-mode effective address calculation
|
||||||
|
T_EAV trace V-mode effective address calculation
|
||||||
|
T_EAI trace I-mode effective address calculation
|
||||||
|
T_FLOW instruction summary
|
||||||
|
T_INST detailed instruction trace
|
||||||
|
T_MODE trace CPU mode changes
|
||||||
|
T_EAAP AP effective address calculation
|
||||||
|
T_DIO disk I/O
|
||||||
|
T_TIO tape I/O
|
||||||
|
T_RIO ring network I/O
|
||||||
|
T_TERM terminal output (tnou[a])
|
||||||
|
T_MAP segmentation
|
||||||
|
T_PCL PCL instructions
|
||||||
|
T_FAULT Faults
|
||||||
|
T_PX Process exchange
|
||||||
|
T_LM License manager
|
||||||
|
T_TLB STLB and IOTLB changes
|
||||||
|
T_REGS Puts into registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define T_EAR 0x00000001
|
||||||
|
#define T_EAV 0x00000002
|
||||||
|
#define T_EAI 0x00000004
|
||||||
|
#define T_INST 0x00000008
|
||||||
|
#define T_FLOW 0x00000010
|
||||||
|
#define T_MODE 0x00000020
|
||||||
|
#define T_EAAP 0x00000040
|
||||||
|
#define T_DIO 0x00000080
|
||||||
|
#define T_MAP 0x00000100
|
||||||
|
#define T_PCL 0x00000200
|
||||||
|
#define T_FAULT 0x00000400
|
||||||
|
#define T_PX 0x00000800
|
||||||
|
#define T_TIO 0x00001000
|
||||||
|
#define T_TERM 0x00002000
|
||||||
|
#define T_RIO 0x00004000
|
||||||
|
#define T_LM 0x00008000
|
||||||
|
#define T_PUT 0x00010000
|
||||||
|
#define T_GET 0x00020000
|
||||||
|
#define T_EAS 0x00040000
|
||||||
|
#define T_TLB 0x00080000
|
||||||
|
#define T_REGS 0x00100000
|
||||||
|
|
||||||
|
#ifdef NOTRACE
|
||||||
|
#define TRACE(flags, formatargs...)
|
||||||
|
#define TRACEA(formatargs...)
|
||||||
|
#else
|
||||||
|
#define TRACE(flags, formatargs...) if (gv.traceflags & (flags)) fprintf(gv.tracefile,formatargs)
|
||||||
|
#define TRACEA(formatargs...) fprintf(gv.tracefile,formatargs)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* In SR modes, Prime CPU registers are mapped to memory locations
|
/* In SR modes, Prime CPU registers are mapped to memory locations
|
||||||
0-'37, but only 0-7 are user accessible. In the post-P300
|
0-'37, but only 0-7 are user accessible. In the post-P300
|
||||||
architecture, these addresses map to the live register file.
|
architecture, these addresses map to the live register file.
|
||||||
@@ -147,8 +394,6 @@ gv.tracetriggered = 1; this simulates the Ctrl-t.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "regs.h"
|
#include "regs.h"
|
||||||
typedef unsigned int ea_t; /* effective address */
|
|
||||||
typedef unsigned int pa_t; /* physical address */
|
|
||||||
|
|
||||||
/* procs needing forward declarations */
|
/* procs needing forward declarations */
|
||||||
|
|
||||||
@@ -268,63 +513,9 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
|
|||||||
|
|
||||||
#define RESTRICTR(rpring) if ((rpring) & RINGMASK32) fault(RESTRICTFAULT, 0, 0);
|
#define RESTRICTR(rpring) if ((rpring) & RINGMASK32) fault(RESTRICTFAULT, 0, 0);
|
||||||
|
|
||||||
/* trace flags to control aspects of emulator tracing:
|
|
||||||
|
|
||||||
T_EAR trace R-mode effective address calculation
|
|
||||||
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
|
|
||||||
T_DIO disk I/O
|
|
||||||
T_TIO tape I/O
|
|
||||||
T_RIO ring network I/O
|
|
||||||
T_TERM terminal output (tnou[a])
|
|
||||||
T_MAP segmentation
|
|
||||||
T_PCL PCL instructions
|
|
||||||
T_FAULT Faults
|
|
||||||
T_PX Process exchange
|
|
||||||
T_LM License manager
|
|
||||||
T_TLB STLB and IOTLB changes
|
|
||||||
T_SMLC SMLC device I/O
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define T_EAR 0x00000001
|
|
||||||
#define T_EAV 0x00000002
|
|
||||||
#define T_EAI 0x00000004
|
|
||||||
#define T_INST 0x00000008
|
|
||||||
#define T_FLOW 0x00000010
|
|
||||||
#define T_MODE 0x00000020
|
|
||||||
#define T_EAAP 0x00000040
|
|
||||||
#define T_DIO 0x00000080
|
|
||||||
#define T_MAP 0x00000100
|
|
||||||
#define T_PCL 0x00000200
|
|
||||||
#define T_FAULT 0x00000400
|
|
||||||
#define T_PX 0x00000800
|
|
||||||
#define T_TIO 0x00001000
|
|
||||||
#define T_TERM 0x00002000
|
|
||||||
#define T_RIO 0x00004000
|
|
||||||
#define T_LM 0x00008000
|
|
||||||
#define T_PUT 0x00010000
|
|
||||||
#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 BITMASK16(b) (0x8000 >> ((b)-1))
|
||||||
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
|
#define BITMASK32(b) ((unsigned int)(0x80000000) >> ((b)-1))
|
||||||
|
|
||||||
#ifdef NOTRACE
|
|
||||||
#define TRACE(flags, formatargs...)
|
|
||||||
#define TRACEA(formatargs...)
|
|
||||||
#else
|
|
||||||
#define TRACE(flags, formatargs...) if (gv.traceflags & (flags)) fprintf(gv.tracefile,formatargs)
|
|
||||||
#define TRACEA(formatargs...) fprintf(gv.tracefile,formatargs)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* traceprocs is an array of (operating system) procedure names we're
|
/* traceprocs is an array of (operating system) procedure names we're
|
||||||
tracing, with flags and associated data
|
tracing, with flags and associated data
|
||||||
|
|
||||||
@@ -358,130 +549,10 @@ static unsigned short firstbdx = 0; /* backstop sleep flag */
|
|||||||
|
|
||||||
static unsigned short cpuid = 15; /* STPM CPU model, set with -cpuid */
|
static unsigned short cpuid = 15; /* STPM CPU model, set with -cpuid */
|
||||||
|
|
||||||
/* STLB cache structure is defined here; the actual stlb is in gv.
|
|
||||||
There are several different styles on Prime models. This is
|
|
||||||
modeled after the 6350 STLB, but is only 1-way associative.
|
|
||||||
The hit rate has been measured to be over 99.8% with a single
|
|
||||||
user.
|
|
||||||
|
|
||||||
Instead of using a valid/invalid bit, a segment number of 0xFFFF
|
|
||||||
(note that the fault, ring, and E bits are set) means "invalid",
|
|
||||||
since it won't match any 12-bit segment number. This eliminates
|
|
||||||
testing the valid bit in mapva.
|
|
||||||
|
|
||||||
As a speed-up, the unmodified bit is stored in access[2], where
|
|
||||||
Ring 2 access should be kept. This makes the structure exactly 16
|
|
||||||
bytes, so indexing into the table can use a left shift 4
|
|
||||||
instruction rather than a multiply by 20. It saves a multiply in
|
|
||||||
the fast path of a _very_ speed-critical routine (mapva).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define STLBENTS 512
|
|
||||||
#define STLB_UNMODIFIED_BIT 2 /* stored in access[2] */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned int pmaddr; /* Prime phys addr of page table flag word */
|
|
||||||
unsigned int ppa; /* physical page address (PPN << 10) */
|
|
||||||
unsigned short procid; /* process id for segments >= '4000 */
|
|
||||||
short seg; /* segment number (0-0xFFF), 0xFFFF = invalid */
|
|
||||||
char access[4]; /* ring n access rights */
|
|
||||||
//char unmodified; /* 1 = page not modified, 0 = modified */
|
|
||||||
//char shared; /* 1 if page is shared and can't be cached */
|
|
||||||
//char valid; /* 1 if STLB entry is valid, zero otherwise */
|
|
||||||
#ifndef NOTRACE
|
|
||||||
unsigned int load_ic; /* instruction where STLB was loaded, (debug) */
|
|
||||||
#endif
|
|
||||||
} stlbe_t;
|
|
||||||
|
|
||||||
/* The IOTLB stores translations for each page of the I/O segments 0-3 */
|
|
||||||
|
|
||||||
#define IOTLBENTS 64*4
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned int ppa; /* physical page address (PPN << 10) */
|
|
||||||
char valid; /* 1 if IOTLB entry is valid, zero otherwise */
|
|
||||||
} iotlbe_t;
|
|
||||||
|
|
||||||
/* maximum indirect levels is 8 according to T&M CPUT4 */
|
/* maximum indirect levels is 8 according to T&M CPUT4 */
|
||||||
|
|
||||||
#define INDLEVELS 8
|
#define INDLEVELS 8
|
||||||
|
|
||||||
/* the emulator uses a special, very small address translation cache
|
|
||||||
to hold the virtual page address and corresponding MEM[] pointer
|
|
||||||
for a few special pages:
|
|
||||||
|
|
||||||
- the 4 base registers (PBBR, SBBR, LBBR, XBBR)
|
|
||||||
- the current instruction page (RPBR)
|
|
||||||
- sector zero (S0BR) of the current procedure
|
|
||||||
- field address registers 0 and 1 (F0BR, F1BR)
|
|
||||||
- "unknown", used for indirect references (UNBR)
|
|
||||||
|
|
||||||
When an effective address is calculated, eap is set to point to one
|
|
||||||
of these cache entries. If the EA, which is a virtual address,
|
|
||||||
references the same page as the cache entry pointed to by eap, then
|
|
||||||
the mapva call can be bypassed and the physical memory address
|
|
||||||
calculated using the cache. If the cache can't be used, either
|
|
||||||
because the entry is invalid, points to a different virtual page,
|
|
||||||
or the access isn't allowed (only for writes), mapva is called to
|
|
||||||
do the mapping and (assuming it doesn't fault) the eap cache entry
|
|
||||||
is updated.
|
|
||||||
|
|
||||||
This special cache is invalidated when the STLB is changed, a ring
|
|
||||||
change occurs, on process exchange, and on LPSW. For reads, no
|
|
||||||
access checking is needed when the cache is used: the cache entry
|
|
||||||
is either valid, meaning that the program has at least read access
|
|
||||||
to the page, or the cache entry is invalid (special value of
|
|
||||||
0x000000FF, which is not a virtual page address - the right 10 bits
|
|
||||||
must be zero for the start of a page), in which case mapva is
|
|
||||||
called.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
IMPORTANT NOTE: bit 4 MUST BE CHECKED before all write references!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define PBBR 0
|
|
||||||
#define SBBR 1
|
|
||||||
#define LBBR 2
|
|
||||||
#define XBBR 3
|
|
||||||
#define RPBR 4
|
|
||||||
#define S0BR 5
|
|
||||||
#define F0BR 6
|
|
||||||
#define F1BR 7
|
|
||||||
#define UNBR 8
|
|
||||||
#define BRP_SIZE 9
|
|
||||||
|
|
||||||
/* NOTE: vpn is a segment number/word offset Prime virtual address
|
|
||||||
corresponding to the physical page of memory in memp. The high-
|
|
||||||
order fault bit of vpn is never set. The ring and extension bits
|
|
||||||
are used to store the 3-bit access field from the STLB for the
|
|
||||||
current ring.
|
|
||||||
|
|
||||||
All brp entries are invalidated by PCL and PRTN when the ring
|
|
||||||
changes, ITLB, PTLB, and LIOT (STLB changes), when OWNERL changes
|
|
||||||
(process exchange), and on LPSW.
|
|
||||||
|
|
||||||
Storing the access bits in the vpn allows use of of the brp cache
|
|
||||||
for write accesses as well as read accesses. Only bit 4 (write
|
|
||||||
allowed) is used, but since a 3-bit value comes back from mapva,
|
|
||||||
it's easier just to put it all in vpn.
|
|
||||||
|
|
||||||
IMPORTANT NOTE: the "get" calls do not store the access field in
|
|
||||||
the brp cache entry; the first write to a page must clear the "page
|
|
||||||
unmodified" bit in the Primos page maps, and mapva is the only way
|
|
||||||
to do this. So the first "put" has to go through mapva. An
|
|
||||||
alternative would be to store the page map pointer in brp and use
|
|
||||||
bit 3 of vpn as a flag for whether the page map has to be modified,
|
|
||||||
but this is more work for probably little gain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned short *memp; /* MEM[] physical page address */
|
|
||||||
ea_t vpn; /* corresponding virtual page address */
|
|
||||||
} brp_t;
|
|
||||||
|
|
||||||
/* the dispatch table for generic instructions:
|
/* the dispatch table for generic instructions:
|
||||||
- bits 1-2 are the class (0-3)
|
- bits 1-2 are the class (0-3)
|
||||||
- bits 3-6 are always zero
|
- bits 3-6 are always zero
|
||||||
@@ -490,78 +561,6 @@ typedef struct {
|
|||||||
|
|
||||||
void *disp_gen[4096]; /* generic dispatch table */
|
void *disp_gen[4096]; /* generic dispatch table */
|
||||||
|
|
||||||
/* "gv" is a static structure used to hold "hot" global variables. These
|
|
||||||
are pointed to by a dedicated register, so that the usual PowerPC global
|
|
||||||
variable instructions aren't needed: these variables can be directly
|
|
||||||
referenced by instructions as long as the structure is < 16K bytes. */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
int memlimit; /* user's desired memory limit (-mem) */
|
|
||||||
|
|
||||||
int intvec; /* currently raised interrupt (if >= zero) */
|
|
||||||
|
|
||||||
unsigned int instcount; /* global instruction count */
|
|
||||||
|
|
||||||
brp_t brp[BRP_SIZE]; /* PB, SB, LB, XB, RP, S0, F0, F1, UN */
|
|
||||||
|
|
||||||
unsigned short inhcount; /* number of instructions to stay inhibited */
|
|
||||||
|
|
||||||
unsigned int instpermsec; /* instructions executed per millisecond */
|
|
||||||
|
|
||||||
stlbe_t stlb[STLBENTS]; /* the STLB: Segmentation Translation Lookaside Buffer */
|
|
||||||
|
|
||||||
iotlbe_t iotlb[IOTLBENTS]; /* the IOTLB: I/O Translation Lookaside Buffer */
|
|
||||||
|
|
||||||
unsigned int prevpc; /* backed program counter */
|
|
||||||
|
|
||||||
unsigned short amask; /* address mask */
|
|
||||||
|
|
||||||
int pmap32bits; /* true if 32-bit page maps */
|
|
||||||
|
|
||||||
int pmap32mask; /* mask for 32-bit page maps */
|
|
||||||
|
|
||||||
int csoffset; /* concealed stack segment offset */
|
|
||||||
|
|
||||||
unsigned int livereglim; /* 010 if seg enabled, 040 if disabled */
|
|
||||||
|
|
||||||
int mapvacalls; /* # of mapva calls */
|
|
||||||
int mapvamisses; /* STLB misses */
|
|
||||||
int supercalls; /* brp supercache hits */
|
|
||||||
int supermisses; /* brp supercache misses */
|
|
||||||
|
|
||||||
void *disp_rmr[128]; /* R-mode memory ref dispatch table */
|
|
||||||
void *disp_vmr[128]; /* V-mode memory ref dispatch table */
|
|
||||||
|
|
||||||
#ifndef NOTRACE
|
|
||||||
|
|
||||||
/* traceflags is the variable used to test tracing of each instruction
|
|
||||||
traceuser is the user number to trace, 0 meaning any user
|
|
||||||
traceseg is the procedure segment number to trace, 0 meaning any
|
|
||||||
savetraceflags hold the real traceflags, while "traceflags" switches
|
|
||||||
on and off for each instruction
|
|
||||||
|
|
||||||
TRACEUSER is a macro that is true if the current user is being traced
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MAXRPQ 8
|
|
||||||
|
|
||||||
FILE *tracefile; /* trace.log file */
|
|
||||||
int traceflags; /* each bit is a trace flag */
|
|
||||||
int savetraceflags;
|
|
||||||
unsigned short traceuser; /* OWNERL to trace */
|
|
||||||
short traceseg; /* RPH segment # to trace */
|
|
||||||
short numtraceprocs; /* # of procedures we're tracing */
|
|
||||||
unsigned int traceinstcount; /* only trace if instcount > this */
|
|
||||||
short tracetriggered; /* Ctrl-T on console toggles tracing */
|
|
||||||
short tracerpqx; /* rpq index to store next RP */
|
|
||||||
unsigned int tracerpq[MAXRPQ];/* last 16 locations executed */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} gv_t;
|
|
||||||
|
|
||||||
static gv_t gv;
|
|
||||||
|
|
||||||
brp_t *eap;
|
brp_t *eap;
|
||||||
|
|
||||||
static jmp_buf jmpbuf; /* for longjumps to the fetch loop */
|
static jmp_buf jmpbuf; /* for longjumps to the fetch loop */
|
||||||
@@ -659,9 +658,7 @@ static unsigned short *physmem = NULL; /* system's physical memory */
|
|||||||
#define LASTFAULT 077
|
#define LASTFAULT 077
|
||||||
|
|
||||||
//static ea_t tnoua_ea=0, tnou_ea=0, tsrc_ea=0;
|
//static ea_t tnoua_ea=0, tnou_ea=0, tsrc_ea=0;
|
||||||
static int noclock; /* -noclock arg */
|
|
||||||
static int domemdump; /* -memdump arg */
|
static int domemdump; /* -memdump arg */
|
||||||
static int dolinecleararg; /* -dolineclear arg */
|
|
||||||
|
|
||||||
static int tport; /* -tport option (incoming terminals) */
|
static int tport; /* -tport option (incoming terminals) */
|
||||||
static int nport; /* -nport option (PNC/Ringnet) */
|
static int nport; /* -nport option (PNC/Ringnet) */
|
||||||
@@ -1132,9 +1129,15 @@ static inline unsigned short get16(ea_t ea) {
|
|||||||
|
|
||||||
static unsigned short get16trap(ea_t ea) {
|
static unsigned short get16trap(ea_t ea) {
|
||||||
|
|
||||||
|
unsigned short zzz;
|
||||||
|
|
||||||
ea = ea & 0xFFFF;
|
ea = ea & 0xFFFF;
|
||||||
if (ea < 7)
|
if (ea < 7)
|
||||||
return getcrs16(memtocrs[ea]);
|
{
|
||||||
|
zzz = getcrs16(memtocrs[ea]);
|
||||||
|
TRACE(T_REGS, " get16trap: ea %012o contents %06o\n", ea, zzz);
|
||||||
|
return zzz;
|
||||||
|
}
|
||||||
if (ea == 7) /* PC */
|
if (ea == 7) /* PC */
|
||||||
return RPL;
|
return RPL;
|
||||||
RESTRICTR(RP);
|
RESTRICTR(RP);
|
||||||
@@ -1306,16 +1309,32 @@ static long long get64r(ea_t ea, ea_t rpring) {
|
|||||||
page instead of on every 16-bit fetch from the instruction stream.
|
page instead of on every 16-bit fetch from the instruction stream.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline unsigned short iget16t(ea_t ea) {
|
#ifdef FAST
|
||||||
eap = &gv.brp[RPBR];
|
|
||||||
return get16t(ea);
|
unsigned short iget16t(ea_t ea) {
|
||||||
|
unsigned short access;
|
||||||
|
|
||||||
|
if (*(int *)&ea >= 0) {
|
||||||
|
gv.brp[RPBR].memp = MEM + (mapva(ea, RP, RACC, &access) & 0xFFFFFC00);
|
||||||
|
gv.brp[RPBR].vpn = ea & 0x0FFFFC00;
|
||||||
|
return swap16(gv.brp[RPBR].memp[ea & 0x3FF]);
|
||||||
|
}
|
||||||
|
return get16trap(ea);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned short iget16(ea_t ea) {
|
static inline unsigned short iget16(ea_t ea) {
|
||||||
eap = &gv.brp[RPBR];
|
|
||||||
return get16(ea);
|
if ((ea & 0x8FFFFC00) == (gv.brp[RPBR].vpn & 0x0FFFFFFF))
|
||||||
|
return swap16(gv.brp[RPBR].memp[ea & 0x3FF]);
|
||||||
|
else
|
||||||
|
return iget16t(ea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define iget16(ea) get16((ea))
|
||||||
|
#define iget16t(ea) get16t((ea))
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void put16(unsigned short value, ea_t ea) {
|
static inline void put16(unsigned short value, ea_t ea) {
|
||||||
unsigned short access;
|
unsigned short access;
|
||||||
|
|
||||||
@@ -1695,8 +1714,6 @@ static int devpoll[64] = {0};
|
|||||||
'35 = devamlc: 4th AMLC (16 lines)
|
'35 = devamlc: 4th AMLC (16 lines)
|
||||||
'45 = devdisk: 7th disk controller (8 drives)
|
'45 = devdisk: 7th disk controller (8 drives)
|
||||||
'46 = devdisk: 8th disk controller (8 drives)
|
'46 = devdisk: 8th disk controller (8 drives)
|
||||||
'50 = devsmlc: 1st HSSMLC/MDLC (4 lines)
|
|
||||||
'51 = devsmlc: 2nd HSSMLC/MDLC (4 lines)
|
|
||||||
'52 = devamlc: 3rd AMLC (16 lines)
|
'52 = devamlc: 3rd AMLC (16 lines)
|
||||||
'53 = devamlc: 2nd AMLC (16 lines)
|
'53 = devamlc: 2nd AMLC (16 lines)
|
||||||
'54 = devamlc: 1st AMLC (16 lines)
|
'54 = devamlc: 1st AMLC (16 lines)
|
||||||
@@ -1708,7 +1725,7 @@ static int (*devmap[64])(int, int, int) = {
|
|||||||
/* '2x */ devcp,devnone,devdisk,devdisk,devdisk,devdisk,devdisk,devdisk,
|
/* '2x */ devcp,devnone,devdisk,devdisk,devdisk,devdisk,devdisk,devdisk,
|
||||||
/* '3x */ devnone,devnone,devamlc,devnone,devnone,devamlc,devnone,devnone,
|
/* '3x */ devnone,devnone,devamlc,devnone,devnone,devamlc,devnone,devnone,
|
||||||
/* '4x */ devnone,devnone,devnone,devnone,devnone,devdisk,devdisk,devnone,
|
/* '4x */ devnone,devnone,devnone,devnone,devnone,devdisk,devdisk,devnone,
|
||||||
/* '5x */ devsmlc,devsmlc,devamlc,devamlc,devamlc,devnone,devnone,devnone,
|
/* '5x */ devnone,devnone,devamlc,devamlc,devamlc,devnone,devnone,devnone,
|
||||||
/* '6x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
/* '6x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
||||||
/* '7x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone};
|
/* '7x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone};
|
||||||
|
|
||||||
@@ -1722,7 +1739,6 @@ static int (*devmap[64])(int, int, int) = {
|
|||||||
'20 = devcp: clock / VCP / SOC
|
'20 = devcp: clock / VCP / SOC
|
||||||
'26 = devdisk: 1st disk controller (8 drives)
|
'26 = devdisk: 1st disk controller (8 drives)
|
||||||
'27 = devdisk: 2nd disk controller (8 drives)
|
'27 = devdisk: 2nd disk controller (8 drives)
|
||||||
'50 = devsmlc: 1st HSSMLC/MDLC (4 lines)
|
|
||||||
'54 = 1st amlc (terminal) controller (16 lines)
|
'54 = 1st amlc (terminal) controller (16 lines)
|
||||||
'53 = devamlc: 2nd AMLC (16 lines)
|
'53 = devamlc: 2nd AMLC (16 lines)
|
||||||
*/
|
*/
|
||||||
@@ -1733,7 +1749,7 @@ static int (*devmap[64])(int, int, int) = {
|
|||||||
/* '2x */ devcp,devnone,devnone,devnone,devnone,devnone,devdisk,devdisk,
|
/* '2x */ devcp,devnone,devnone,devnone,devnone,devnone,devdisk,devdisk,
|
||||||
/* '3x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
/* '3x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
||||||
/* '4x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
/* '4x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
||||||
/* '5x */ devsmlc,devnone,devnone,devamlc,devamlc,devnone,devnone,devnone,
|
/* '5x */ devnone,devnone,devnone,devamlc,devamlc,devnone,devnone,devnone,
|
||||||
/* '6x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
/* '6x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone,
|
||||||
/* '7x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone};
|
/* '7x */ devnone,devnone,devnone,devnone,devnone,devnone,devnone,devnone};
|
||||||
#endif
|
#endif
|
||||||
@@ -1772,7 +1788,7 @@ char *keystring(unsigned short keys) {
|
|||||||
*sp++ = 'L';
|
*sp++ = 'L';
|
||||||
memcpy(sp, modes[(keys>>10) & 7], 3);
|
memcpy(sp, modes[(keys>>10) & 7], 3);
|
||||||
sp += 3;
|
sp += 3;
|
||||||
if (!(keys & 01000)) /* float exception enabled */
|
if (keys & 01000 == 0) /* float exception enabled */
|
||||||
*sp++ = 'F';
|
*sp++ = 'F';
|
||||||
if (keys & 0400) /* int exception enabled */
|
if (keys & 0400) /* int exception enabled */
|
||||||
*sp++ = 'I';
|
*sp++ = 'I';
|
||||||
@@ -2248,7 +2264,7 @@ special:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (class < 2) { /* class 0/1 */
|
if (class < 2) { /* class 0/1 */
|
||||||
ea = iget16t(RP); /* get A from next word */
|
ea = iget16(RP); /* get A from next word */
|
||||||
INCRP;
|
INCRP;
|
||||||
TRACE(T_EAR, " Class %d, new ea=%o\n", class, ea);
|
TRACE(T_EAR, " Class %d, new ea=%o\n", class, ea);
|
||||||
if (class == 1)
|
if (class == 1)
|
||||||
@@ -2277,7 +2293,7 @@ special:
|
|||||||
|
|
||||||
} else if (i && x) { /* class 2/3, ix=11 */
|
} else if (i && x) { /* class 2/3, ix=11 */
|
||||||
TRACE(T_EAR, " class 2/3, ix=11\n");
|
TRACE(T_EAR, " class 2/3, ix=11\n");
|
||||||
ea = iget16t(RP); /* get A from next word */
|
ea = iget16(RP); /* get A from next word */
|
||||||
INCRP;
|
INCRP;
|
||||||
TRACE(T_EAR, " ea=%o\n", ea);
|
TRACE(T_EAR, " ea=%o\n", ea);
|
||||||
if (class == 3) {
|
if (class == 3) {
|
||||||
@@ -2355,7 +2371,7 @@ special:
|
|||||||
static ea_t apea(unsigned short *bitarg) {
|
static ea_t apea(unsigned short *bitarg) {
|
||||||
unsigned short ibr, ea_s, ea_w, bit, br, a;
|
unsigned short ibr, ea_s, ea_w, bit, br, a;
|
||||||
unsigned int utempl;
|
unsigned int utempl;
|
||||||
ea_t ea, ip, iwea;
|
ea_t ea, ip;
|
||||||
|
|
||||||
eap = &gv.brp[RPBR];
|
eap = &gv.brp[RPBR];
|
||||||
utempl = get32(RP);
|
utempl = get32(RP);
|
||||||
@@ -2381,11 +2397,8 @@ static ea_t apea(unsigned short *bitarg) {
|
|||||||
bit = get16(INCVA(ea,2)) >> 12;
|
bit = get16(INCVA(ea,2)) >> 12;
|
||||||
else
|
else
|
||||||
bit = 0;
|
bit = 0;
|
||||||
iwea = ea;
|
|
||||||
ea = ip;
|
ea = ip;
|
||||||
TRACE(T_EAAP, " After indirect, AP ea = %o/%o, bit=%d %s\n", ea>>16, ea & 0xFFFF, bit, searchloadmap(ea,' '));
|
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)
|
if (bitarg != NULL)
|
||||||
*bitarg = bit;
|
*bitarg = bit;
|
||||||
@@ -4375,7 +4388,7 @@ int main (int argc, char **argv) {
|
|||||||
#define XRBRACE 0375
|
#define XRBRACE 0375
|
||||||
|
|
||||||
printf("[Prime Emulator ver %s %s]\n", REV, __DATE__);
|
printf("[Prime Emulator ver %s %s]\n", REV, __DATE__);
|
||||||
printf("[Copyright (C) 2005-2021 Jim Wilcoxson prirun@gmail.com]\n");
|
printf("[Copyright (C) 2005-2019 Jim Wilcoxson prirun@gmail.com]\n");
|
||||||
if (argc > 1 && (strcmp(argv[1],"--version") == 0)) {
|
if (argc > 1 && (strcmp(argv[1],"--version") == 0)) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
@@ -4404,16 +4417,12 @@ int main (int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
setvbuf(stderr, NULL, _IONBF, 0);
|
setvbuf(stderr, NULL, _IONBF, 0);
|
||||||
|
|
||||||
/* initialize global variables
|
/* initialize global variables */
|
||||||
|
|
||||||
NOTE: if instpermsec is off by more than a factor of 2, it causes
|
|
||||||
some minor clock skew problems during the first few seconds of
|
|
||||||
system boot. There is debug code in emdev.h/devcp to see this. */
|
|
||||||
|
|
||||||
gv.intvec = -1;
|
gv.intvec = -1;
|
||||||
gv.instcount = 0;
|
gv.instcount = 0;
|
||||||
gv.inhcount = 0;
|
gv.inhcount = 0;
|
||||||
gv.instpermsec = 40000;
|
gv.instpermsec = 2000;
|
||||||
gv.livereglim = 040;
|
gv.livereglim = 040;
|
||||||
gv.mapvacalls = 0;
|
gv.mapvacalls = 0;
|
||||||
gv.mapvamisses = 0;
|
gv.mapvamisses = 0;
|
||||||
@@ -4457,9 +4466,7 @@ int main (int argc, char **argv) {
|
|||||||
|
|
||||||
#include "dispatch.h"
|
#include "dispatch.h"
|
||||||
|
|
||||||
noclock = 0;
|
|
||||||
domemdump = 0;
|
domemdump = 0;
|
||||||
dolinecleararg = 0;
|
|
||||||
bootarg = NULL;
|
bootarg = NULL;
|
||||||
bootfile[0] = 0;
|
bootfile[0] = 0;
|
||||||
gv.pmap32bits = 0;
|
gv.pmap32bits = 0;
|
||||||
@@ -4476,15 +4483,9 @@ int main (int argc, char **argv) {
|
|||||||
while (i+1 < argc && argv[i+1][0] != '-')
|
while (i+1 < argc && argv[i+1][0] != '-')
|
||||||
readloadmap(argv[++i], 1);
|
readloadmap(argv[++i], 1);
|
||||||
|
|
||||||
} else if (strcmp(argv[i],"-noclock") == 0) {
|
|
||||||
noclock = 1;
|
|
||||||
|
|
||||||
} else if (strcmp(argv[i],"-memdump") == 0) {
|
} else if (strcmp(argv[i],"-memdump") == 0) {
|
||||||
domemdump = 1;
|
domemdump = 1;
|
||||||
|
|
||||||
} else if (strcmp(argv[i],"-dolineclear") == 0) {
|
|
||||||
dolinecleararg = 1;
|
|
||||||
|
|
||||||
} else if (strcmp(argv[i],"-ss") == 0) {
|
} else if (strcmp(argv[i],"-ss") == 0) {
|
||||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||||
sscanf(argv[++i],"%o", &templ);
|
sscanf(argv[++i],"%o", &templ);
|
||||||
@@ -4623,18 +4624,16 @@ int main (int argc, char **argv) {
|
|||||||
setlinebuf(gv.tracefile);
|
setlinebuf(gv.tracefile);
|
||||||
else if (strcmp(argv[i],"tlb") == 0)
|
else if (strcmp(argv[i],"tlb") == 0)
|
||||||
gv.traceflags |= T_TLB;
|
gv.traceflags |= T_TLB;
|
||||||
else if (strcmp(argv[i],"smlc") == 0)
|
else if (strcmp(argv[i],"regs") == 0)
|
||||||
gv.traceflags |= T_SMLC;
|
gv.traceflags |= T_REGS;
|
||||||
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)
|
else if (isdigit(argv[i][0]) && strlen(argv[i]) <= 3 && sscanf(argv[i],"%d", &templ) == 1)
|
||||||
gv.traceuser = 0100000 | (templ<<6); /* form OWNERL for user # */
|
gv.traceuser = 0100000 | (templ<<6); /* form OWNERL for user # */
|
||||||
|
else if (isdigit(argv[i][0]) && sscanf(argv[i],"%d", &templ) == 1)
|
||||||
|
gv.traceinstcount = templ;
|
||||||
else if (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1)
|
else if (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1)
|
||||||
gv.traceuser = templ; /* specify OWNERL directly */
|
gv.traceuser = templ; /* specify OWNERL directly */
|
||||||
else if (strlen(argv[i]) == 4 && sscanf(argv[i],"%o", &templ) == 1)
|
else if (strlen(argv[i]) == 4 && sscanf(argv[i],"%o", &templ) == 1)
|
||||||
gv.traceseg = templ; /* specify RPH segno */
|
gv.traceseg = templ; /* specify RPH segno */
|
||||||
else if (argv[i][0] == '#' && sscanf(argv[i]+1,"%d", &templ) == 1)
|
|
||||||
gv.traceinstcount = templ;
|
|
||||||
else if (strlen(argv[i]) <= 8 && argv[i][0] != '-') {
|
else if (strlen(argv[i]) <= 8 && argv[i][0] != '-') {
|
||||||
if (gv.numtraceprocs >= MAXTRACEPROCS)
|
if (gv.numtraceprocs >= MAXTRACEPROCS)
|
||||||
fprintf(stderr,"Only %d trace procs are allowed\n", MAXTRACEPROCS);
|
fprintf(stderr,"Only %d trace procs are allowed\n", MAXTRACEPROCS);
|
||||||
@@ -4725,7 +4724,6 @@ int main (int argc, char **argv) {
|
|||||||
/* finish setting up tracing after all options are read, ie, maps */
|
/* finish setting up tracing after all options are read, ie, maps */
|
||||||
|
|
||||||
#ifndef NOTRACE
|
#ifndef NOTRACE
|
||||||
TRACEA("Trace file initialized\n");
|
|
||||||
TRACEA("Trace flags = 0x%x\n", gv.traceflags);
|
TRACEA("Trace flags = 0x%x\n", gv.traceflags);
|
||||||
gv.savetraceflags = gv.traceflags;
|
gv.savetraceflags = gv.traceflags;
|
||||||
gv.traceflags = 0;
|
gv.traceflags = 0;
|
||||||
@@ -4735,14 +4733,6 @@ int main (int argc, char **argv) {
|
|||||||
TRACEA("Tracing enabled for all users\n");
|
TRACEA("Tracing enabled for all users\n");
|
||||||
if (gv.traceinstcount != 0)
|
if (gv.traceinstcount != 0)
|
||||||
TRACEA("Tracing enabled after instruction %u\n", gv.traceinstcount);
|
TRACEA("Tracing enabled after instruction %u\n", gv.traceinstcount);
|
||||||
if (gv.traceseg != 0)
|
|
||||||
{
|
|
||||||
TRACEA("Tracing enabled for segment %04o\n", gv.traceseg);
|
|
||||||
/* This could be splattering other settings that aren't really
|
|
||||||
compatible with RPH trace. C'est la vie? */
|
|
||||||
gv.savetraceflags |= T_FLOW;
|
|
||||||
gv.tracetriggered = 0;
|
|
||||||
}
|
|
||||||
for (i=0; i<gv.numtraceprocs; i++) {
|
for (i=0; i<gv.numtraceprocs; i++) {
|
||||||
for (j=0; j<numsyms; j++) {
|
for (j=0; j<numsyms; j++) {
|
||||||
if (strcasecmp(mapsym[j].symname, traceprocs[i].name) == 0 && mapsym[j].symtype == 'e') {
|
if (strcasecmp(mapsym[j].symname, traceprocs[i].name) == 0 && mapsym[j].symtype == 'e') {
|
||||||
@@ -4803,12 +4793,6 @@ int main (int argc, char **argv) {
|
|||||||
for (i=0; i<9; i++)
|
for (i=0; i<9; i++)
|
||||||
rvec[i] = swap16(rvec[i]);
|
rvec[i] = swap16(rvec[i]);
|
||||||
|
|
||||||
if (rvec[3] != 0) {
|
|
||||||
if (rvec[2] > rvec[1]) {
|
|
||||||
rvec[0] += rvec[3];
|
|
||||||
rvec[1] += rvec[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* If no filename follows -boot, then the sense switches are used to
|
/* If no filename follows -boot, then the sense switches are used to
|
||||||
@@ -4969,11 +4953,6 @@ fetch:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NOTRACE
|
#ifndef NOTRACE
|
||||||
if (gv.traceseg != 0)
|
|
||||||
if (gv.traceseg == (RPH & 0xFFF))
|
|
||||||
gv.tracetriggered = 1;
|
|
||||||
else
|
|
||||||
gv.tracetriggered = 0;
|
|
||||||
gv.traceflags = 0;
|
gv.traceflags = 0;
|
||||||
if (gv.tracetriggered &&
|
if (gv.tracetriggered &&
|
||||||
(gv.instcount >= gv.traceinstcount) &&
|
(gv.instcount >= gv.traceinstcount) &&
|
||||||
@@ -5185,7 +5164,7 @@ fetch:
|
|||||||
|
|
||||||
inst = iget16(RP | ((RPL >= gv.livereglim || (getcrs16(KEYS) & 0016000) == 010000) ? 0 : 0x80000000));
|
inst = iget16(RP | ((RPL >= gv.livereglim || (getcrs16(KEYS) & 0016000) == 010000) ? 0 : 0x80000000));
|
||||||
#else
|
#else
|
||||||
inst = iget16t(RP);
|
inst = iget16(RP);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
INCRP;
|
INCRP;
|
||||||
@@ -6314,33 +6293,15 @@ d_hlt: /* 000000 */
|
|||||||
if (bootarg) {
|
if (bootarg) {
|
||||||
printf("\nCPU halt, instruction #%u at %o/%o %s: %o %o ^%06o^\nA='%o/%d B='%o/%d L='%o/%d X=%o/%d", gv.instcount, RPH, RPL, searchloadmap(gv.prevpc,' '), get16t(gv.prevpc), get16t(gv.prevpc+1), lights, getcrs16(A), getcrs16s(A), getcrs16(B), getcrs16s(B), getcrs32(A), getcrs32s(A), getcrs16(X), getcrs16s(X));
|
printf("\nCPU halt, instruction #%u at %o/%o %s: %o %o ^%06o^\nA='%o/%d B='%o/%d L='%o/%d X=%o/%d", gv.instcount, RPH, RPL, searchloadmap(gv.prevpc,' '), get16t(gv.prevpc), get16t(gv.prevpc+1), lights, getcrs16(A), getcrs16s(A), getcrs16(B), getcrs16s(B), getcrs32(A), getcrs32s(A), getcrs16(X), getcrs16s(X));
|
||||||
while (1) {
|
while (1) {
|
||||||
int n;
|
|
||||||
static int ttydev;
|
|
||||||
ttydev = open("/dev/tty", O_RDWR, 0);
|
|
||||||
if (ttydev < 0) {
|
|
||||||
perror(" error opening /dev/tty");
|
|
||||||
fatal(NULL);
|
|
||||||
}
|
|
||||||
printf("\nPress Enter to continue, h to halt... ");
|
printf("\nPress Enter to continue, h to halt... ");
|
||||||
fflush(stdout);
|
utempa = getchar();
|
||||||
utempa = ' ';
|
|
||||||
n = 0;
|
|
||||||
while (n == 0)
|
|
||||||
n = read(ttydev, &utempa, 1);
|
|
||||||
/* utempa = getchar(); */
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (utempa == '\r' || utempa == '\n')
|
if (utempa == '\r' || utempa == '\n')
|
||||||
{
|
|
||||||
close(ttydev);
|
|
||||||
goto fetch;
|
goto fetch;
|
||||||
}
|
|
||||||
if (utempa == 'h')
|
if (utempa == 'h')
|
||||||
{
|
|
||||||
close(ttydev);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fatal("CPU halt");
|
fatal("CPU halt");
|
||||||
|
|
||||||
d_pim: /* 000205 (R-mode) */
|
d_pim: /* 000205 (R-mode) */
|
||||||
|
|||||||
12
emdev.h
12
emdev.h
@@ -1413,10 +1413,8 @@ void initclock(ea_t datnowea) {
|
|||||||
unixtime = time(NULL);
|
unixtime = time(NULL);
|
||||||
tms = localtime(&unixtime);
|
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);
|
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);
|
||||||
if (! noclock) {
|
|
||||||
put32r0(datnow, datnowea);
|
put32r0(datnow, datnowea);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int devcp (int class, int func, int device) {
|
int devcp (int class, int func, int device) {
|
||||||
@@ -1532,15 +1530,15 @@ int devcp (int class, int func, int device) {
|
|||||||
else if (cpuid >= 15) /* newer machines: 250 ticks/second */
|
else if (cpuid >= 15) /* newer machines: 250 ticks/second */
|
||||||
clkpic = -1250;
|
clkpic = -1250;
|
||||||
TRACE(T_INST, "Clock PIC %d requested, set to %d\n", getcrs16s(A), clkpic);
|
TRACE(T_INST, "Clock PIC %d requested, set to %d\n", getcrs16s(A), clkpic);
|
||||||
ticks = -1;
|
|
||||||
SETCLKPOLL;
|
SETCLKPOLL;
|
||||||
|
ticks = -1;
|
||||||
|
|
||||||
} else if (func == 07) {
|
} else if (func == 07) {
|
||||||
|
TRACE(T_INST, "Clock control register set to '%o\n", getcrs16(A));
|
||||||
if (getcrs16(A) & 020)
|
if (getcrs16(A) & 020)
|
||||||
clkrate = 102.4;
|
clkrate = 102.4;
|
||||||
else
|
else
|
||||||
clkrate = 3.2;
|
clkrate = 3.2;
|
||||||
TRACE(T_INST, "Clock control register set to '%o\n", getcrs16(A));
|
|
||||||
ticks = -1;
|
ticks = -1;
|
||||||
SETCLKPOLL;
|
SETCLKPOLL;
|
||||||
|
|
||||||
@@ -1588,7 +1586,7 @@ int devcp (int class, int func, int device) {
|
|||||||
targetticks = elapsedms/(-clkpic*clkrate/1000);
|
targetticks = elapsedms/(-clkpic*clkrate/1000);
|
||||||
#if 0
|
#if 0
|
||||||
if (abs(ticks-targetticks) > 5)
|
if (abs(ticks-targetticks) > 5)
|
||||||
printf("\nClock: target=%d, ticks=%d, offset=%d, ipms=%d, poll=%d\n", targetticks, ticks, ticks-targetticks, gv.instpermsec, devpoll[device]);
|
printf("\nClock: target=%d, ticks=%d, offset=%d\n", targetticks, ticks, ticks-targetticks);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* if the clock gets way out of whack (eg, because of a host
|
/* if the clock gets way out of whack (eg, because of a host
|
||||||
@@ -1631,7 +1629,7 @@ int devcp (int class, int func, int device) {
|
|||||||
XXX: this code should probably be done whether or not the
|
XXX: this code should probably be done whether or not the
|
||||||
clock is running */
|
clock is running */
|
||||||
|
|
||||||
#define IPMTIME 1000
|
#define IPMTIME 5000
|
||||||
|
|
||||||
if ((gv.instcount < previnstcount) || (gv.instcount-previnstcount > gv.instpermsec*IPMTIME)) {
|
if ((gv.instcount < previnstcount) || (gv.instcount-previnstcount > gv.instpermsec*IPMTIME)) {
|
||||||
if (gv.instcount-previnstcount > gv.instpermsec*IPMTIME) {
|
if (gv.instcount-previnstcount > gv.instpermsec*IPMTIME) {
|
||||||
@@ -2226,5 +2224,3 @@ int devdisk (int class, int func, int device) {
|
|||||||
#include "devpnc.h"
|
#include "devpnc.h"
|
||||||
|
|
||||||
#include "devamlc.h"
|
#include "devamlc.h"
|
||||||
|
|
||||||
#include "devsmlc.h"
|
|
||||||
|
|||||||
80
fp.h
80
fp.h
@@ -40,7 +40,6 @@ http://tima-cmp.imag.fr/~guyot/Cours/Oparithm/english/Op_Ar2.htm
|
|||||||
|
|
||||||
inline void getdp (unsigned long long p, long long *frac64, int *exp32) {
|
inline void getdp (unsigned long long p, long long *frac64, int *exp32) {
|
||||||
|
|
||||||
TRACE(T_FP, " getdp(%016llx)\n", p);
|
|
||||||
*frac64 = p & 0xFFFFFFFFFFFF0000LL; /* unpack fraction */
|
*frac64 = p & 0xFFFFFFFFFFFF0000LL; /* unpack fraction */
|
||||||
*exp32 = (short) (p & 0xFFFFLL); /* unpack SIGNED exponent */
|
*exp32 = (short) (p & 0xFFFFLL); /* unpack SIGNED exponent */
|
||||||
}
|
}
|
||||||
@@ -60,29 +59,22 @@ int prieee8(unsigned long long dp, double *d) {
|
|||||||
/* unpack Prime DPFP */
|
/* unpack Prime DPFP */
|
||||||
|
|
||||||
getdp (dp, &frac64, &exp32);
|
getdp (dp, &frac64, &exp32);
|
||||||
TRACE(T_FP, " prieee8: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
|
||||||
|
|
||||||
/* if negative, change to sign-magnitude */
|
/* if negative, change to sign-magnitude */
|
||||||
|
|
||||||
sign = 0;
|
sign = 0;
|
||||||
if (frac64 < 0) {
|
if (frac64 < 0) {
|
||||||
TRACE(T_FP, " prieee8: changing to sign-magnitude\n");
|
|
||||||
|
|
||||||
/* special case: negative power of 2 */
|
/* special case: negative power of 2 */
|
||||||
|
|
||||||
if (frac64 == 0x8000000000000000LL) {
|
if (frac64 == 0x8000000000000000LL) {
|
||||||
TRACE(T_FP, " prieee8: frac is negative power of 2\n");
|
|
||||||
exp32 += (1023-128);
|
exp32 += (1023-128);
|
||||||
if (exp32 < 0 || exp32 > 0x7fe)
|
if (exp32 < 0 || exp32 > 0x7fe)
|
||||||
{
|
|
||||||
TRACE(T_FP, " prieee8: exp %x out of range\n", exp32);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
frac64 |= ((long long)exp32 << 52);
|
frac64 |= ((long long)exp32 << 52);
|
||||||
*d = *(double *)&frac64;
|
*d = *(double *)&frac64;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
TRACE(T_FP, " prieee8: frac is just negative\n");
|
|
||||||
sign = 0x8000000000000000LL;
|
sign = 0x8000000000000000LL;
|
||||||
frac64 = -frac64;
|
frac64 = -frac64;
|
||||||
}
|
}
|
||||||
@@ -90,7 +82,6 @@ int prieee8(unsigned long long dp, double *d) {
|
|||||||
/* special case: zero */
|
/* special case: zero */
|
||||||
|
|
||||||
} else if (frac64 == 0) {
|
} else if (frac64 == 0) {
|
||||||
TRACE(T_FP, " prieee8: frac is 0\n");
|
|
||||||
*d = 0.0;
|
*d = 0.0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -98,7 +89,6 @@ int prieee8(unsigned long long dp, double *d) {
|
|||||||
/* normalize positive fraction until bit 2 is 1 */
|
/* normalize positive fraction until bit 2 is 1 */
|
||||||
|
|
||||||
while ((frac64 & 0x4000000000000000LL) == 0) {
|
while ((frac64 & 0x4000000000000000LL) == 0) {
|
||||||
TRACE(T_FP, " prieee8: normalizing positive fraction\n");
|
|
||||||
frac64 = frac64 << 1;
|
frac64 = frac64 << 1;
|
||||||
exp32--;
|
exp32--;
|
||||||
}
|
}
|
||||||
@@ -108,10 +98,7 @@ int prieee8(unsigned long long dp, double *d) {
|
|||||||
exp32 += (1023-128) - 1;
|
exp32 += (1023-128) - 1;
|
||||||
#if 1
|
#if 1
|
||||||
if (exp32 < 0 || exp32 > 0x7fe)
|
if (exp32 < 0 || exp32 > 0x7fe)
|
||||||
{
|
|
||||||
TRACE(T_FP, " prieee8: exponent %x out of range\n", exp32);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (exp32 < 0) {
|
if (exp32 < 0) {
|
||||||
*d = 0.0;
|
*d = 0.0;
|
||||||
@@ -126,7 +113,6 @@ int prieee8(unsigned long long dp, double *d) {
|
|||||||
/* pack into an IEEE DPFP, losing the leading 1 bit in the process */
|
/* pack into an IEEE DPFP, losing the leading 1 bit in the process */
|
||||||
|
|
||||||
frac64 = sign | ((long long)exp32 << 52) | ((frac64 >> 10) & 0xfffffffffffffLL);
|
frac64 = sign | ((long long)exp32 << 52) | ((frac64 >> 10) & 0xfffffffffffffLL);
|
||||||
TRACE(T_FP, " prieee8: packed ieee dpfp %016llx\n", frac64);
|
|
||||||
*d = *(double *)&frac64;
|
*d = *(double *)&frac64;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -148,7 +134,7 @@ retry:
|
|||||||
neg = frac64 < 0;
|
neg = frac64 < 0;
|
||||||
exp32 = (frac64 >> 52) & 0x7ff;
|
exp32 = (frac64 >> 52) & 0x7ff;
|
||||||
frac64 &= 0xfffffffffffffLL;
|
frac64 &= 0xfffffffffffffLL;
|
||||||
TRACE(T_FP, "d=%016llx, neg=%x, frac64=%016llx, exp32=%08x, \n", (long long)d, neg, frac64, exp32);
|
//printf("dp=%llx, neg=%d, frac64=%llx, exp32=%d, \n", *(long long *)dp, neg, frac64, exp32);
|
||||||
|
|
||||||
/* special case: NaN & +-infinity */
|
/* special case: NaN & +-infinity */
|
||||||
|
|
||||||
@@ -173,21 +159,12 @@ retry:
|
|||||||
and subnormal */
|
and subnormal */
|
||||||
|
|
||||||
if (exp32 != 0) /* typical IEEE normalized */
|
if (exp32 != 0) /* typical IEEE normalized */
|
||||||
{
|
|
||||||
TRACE(T_FP, " ieeepr8: is normalized\n");
|
|
||||||
frac64 |= 0x10000000000000LL;
|
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 */
|
*p = 0; /* IEEE and Prime zero are the same */
|
||||||
return okay;
|
return okay;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
TRACE(T_FP, " ieeepr8: subnormal value\n");
|
|
||||||
; /* subnormal: no hidden 1 bit */
|
; /* subnormal: no hidden 1 bit */
|
||||||
}
|
|
||||||
|
|
||||||
/* adjust exponent, change sign-magnitude to 2's complement,
|
/* adjust exponent, change sign-magnitude to 2's complement,
|
||||||
and shift fraction into Prime placement (high 48 bits) */
|
and shift fraction into Prime placement (high 48 bits) */
|
||||||
@@ -196,14 +173,12 @@ retry:
|
|||||||
if (neg)
|
if (neg)
|
||||||
frac64 = -frac64;
|
frac64 = -frac64;
|
||||||
frac64 <<= 10;
|
frac64 <<= 10;
|
||||||
TRACE(T_FP, " ieeepr8: de-biased prime-ised frac %016llx exp %08x\n", frac64, exp32);
|
|
||||||
|
|
||||||
/* normalize Prime DPFP */
|
/* normalize Prime DPFP */
|
||||||
|
|
||||||
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
||||||
frac64 = frac64 << 1;
|
frac64 = frac64 << 1;
|
||||||
exp32--;
|
exp32--;
|
||||||
TRACE(T_FP, " ieeepr8: normalized prime frac %016llx exp %08x\n", frac64, exp32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -229,11 +204,8 @@ retry:
|
|||||||
|
|
||||||
if (round)
|
if (round)
|
||||||
if ((frac64 & 0x8000) && ((frac64 & 0x7fffffffffff0000LL) != 0x7fffffffffff0000LL))
|
if ((frac64 & 0x8000) && ((frac64 & 0x7fffffffffff0000LL) != 0x7fffffffffff0000LL))
|
||||||
{
|
|
||||||
/* XXX: should this be a subtract for negative numbers? */
|
/* XXX: should this be a subtract for negative numbers? */
|
||||||
frac64 += 0x10000;
|
frac64 += 0x10000;
|
||||||
TRACE(T_FP, " ieeepr8: rounded frac %016llx\n", frac64);
|
|
||||||
}
|
|
||||||
|
|
||||||
*p = swap64((frac64 & 0xffffffffffff0000LL) | (exp32 & 0xffff));
|
*p = swap64((frac64 & 0xffffffffffff0000LL) | (exp32 & 0xffff));
|
||||||
return okay;
|
return okay;
|
||||||
@@ -288,7 +260,6 @@ unsigned long long dfcm (unsigned long long dp, int *oflow) {
|
|||||||
CLEARC;
|
CLEARC;
|
||||||
*oflow = 0;
|
*oflow = 0;
|
||||||
getdp(dp, &frac64, &exp32);
|
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 != 0) { /* can't normalize zero */
|
||||||
if (frac64 == 0x8000000000000000LL) { /* overflow case? */
|
if (frac64 == 0x8000000000000000LL) { /* overflow case? */
|
||||||
frac64 = 0x4000000000000000LL; /* complement power of 2 */
|
frac64 = 0x4000000000000000LL; /* complement power of 2 */
|
||||||
@@ -319,7 +290,6 @@ unsigned long long norm(unsigned long long dp, int *oflow) {
|
|||||||
|
|
||||||
*oflow = 0;
|
*oflow = 0;
|
||||||
getdp(dp, &frac64, &exp32);
|
getdp(dp, &frac64, &exp32);
|
||||||
TRACE(T_FP, " norm: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
|
||||||
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
||||||
frac64 = frac64 << 1;
|
frac64 = frac64 << 1;
|
||||||
exp32--;
|
exp32--;
|
||||||
@@ -344,16 +314,11 @@ unsigned long long frn(unsigned long long dp, int *oflow) {
|
|||||||
|
|
||||||
*oflow = 0;
|
*oflow = 0;
|
||||||
getdp(dp, &frac64, &exp32);
|
getdp(dp, &frac64, &exp32);
|
||||||
TRACE(T_FP, " frn: unpacked frac %016llx exp %08x\n", frac64, exp32);
|
|
||||||
if (frac64 == 0)
|
if (frac64 == 0)
|
||||||
{
|
|
||||||
TRACE(T_FP, " frn: returning 0\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
doround1 = ((frac64 & 0x18000000000LL) != 0);
|
doround1 = ((frac64 & 0x18000000000LL) != 0);
|
||||||
doround2 = ((frac64 & 0x8000000000LL) != 0) && ((frac64 & 0x7FFFFF0000LL) != 0);
|
doround2 = ((frac64 & 0x8000000000LL) != 0) && ((frac64 & 0x7FFFFF0000LL) != 0);
|
||||||
TRACE(T_FP, " frn: doround1 %x doround2 %x\n", doround1, doround2);
|
|
||||||
if (doround1 || doround2) {
|
if (doround1 || doround2) {
|
||||||
frac64 &= 0xFFFFFF0000000000LL;
|
frac64 &= 0xFFFFFF0000000000LL;
|
||||||
if (frac64 != 0x7FFFFF0000000000LL)
|
if (frac64 != 0x7FFFFF0000000000LL)
|
||||||
@@ -364,10 +329,8 @@ unsigned long long frn(unsigned long long dp, int *oflow) {
|
|||||||
}
|
}
|
||||||
frac64 |= (exp32 & 0xFFFF);
|
frac64 |= (exp32 & 0xFFFF);
|
||||||
frac64 = norm(frac64, oflow);
|
frac64 = norm(frac64, oflow);
|
||||||
TRACE(T_FP, " frn: rounded frac %016llx\n", frac64);
|
|
||||||
return frac64;
|
return frac64;
|
||||||
}
|
}
|
||||||
TRACE(T_FP, " frn: dp %016llx\n", dp);
|
|
||||||
return dp;
|
return dp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,38 +356,27 @@ int fcs (unsigned long long fac, int fop) {
|
|||||||
fop = fop & 0xffffff00;
|
fop = fop & 0xffffff00;
|
||||||
if (fop == 0) /* fix dirty zero */
|
if (fop == 0) /* fix dirty zero */
|
||||||
fopexp = 0;
|
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 ((templ & 0x80000000) == (fop & 0x80000000)) { /* compare signs */
|
||||||
if (facexp == fopexp) /* compare exponents */
|
if (facexp == fopexp) /* compare exponents */
|
||||||
if (templ == fop) { /* compare fractions */
|
if (templ == fop) { /* compare fractions */
|
||||||
TRACE(T_FP, " fcs: frac cmp returning eq / skip 1\n");
|
|
||||||
SETEQ;
|
SETEQ;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (templ < fop) { /* compare fractions */
|
} else if (templ < fop) { /* compare fractions */
|
||||||
TRACE(T_FP, " fcs: frac cmp returning lt / skip 2\n");
|
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else
|
||||||
TRACE(T_FP, " fcs: frac cmp returning gt / skip 0\n");
|
|
||||||
return 0; /* FAC > operand */
|
return 0; /* FAC > operand */
|
||||||
}
|
|
||||||
else if (facexp < fopexp) { /* compare exponents */
|
else if (facexp < fopexp) { /* compare exponents */
|
||||||
TRACE(T_FP, " fcs: exp cmp returning lt / skip 2\n");
|
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else
|
||||||
TRACE(T_FP, " fcs: exp cmp returning gt / skip 0\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
} else if (templ & 0x80000000) {
|
} else if (templ & 0x80000000) {
|
||||||
TRACE(T_FP, " fcs: sign cmp returning lt / skip 2\n");
|
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else
|
||||||
TRACE(T_FP, " fcs: sign cmp returning gt / skip 0\n");
|
|
||||||
return 0; /* FAC > operand */
|
return 0; /* FAC > operand */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* DPFP comparison, for both DFCS (SRV-mode) and DFC (I-mode)
|
/* DPFP comparison, for both DFCS (SRV-mode) and DFC (I-mode)
|
||||||
@@ -452,35 +404,27 @@ int dfcs (unsigned long long fac, long long fop) {
|
|||||||
fop = fop & 0xffffffffffff0000LL;
|
fop = fop & 0xffffffffffff0000LL;
|
||||||
if (fop == 0) /* fix dirty zero */
|
if (fop == 0) /* fix dirty zero */
|
||||||
fopexp = 0;
|
fopexp = 0;
|
||||||
TRACE(T_FP, " dfcs: FAC: %016llx %04x; op: %016llx %04x\n", templl, facexp, fop, fopexp);
|
#if 0
|
||||||
|
printf("dfcs: FAC: %016llx %04x; op: %016llx %04x\n", templl, facexp, fop, fopexp);
|
||||||
|
#endif
|
||||||
if ((templl & 0x8000000000000000LL) == (fop & 0x8000000000000000LL)) { /* compare signs */
|
if ((templl & 0x8000000000000000LL) == (fop & 0x8000000000000000LL)) { /* compare signs */
|
||||||
if (facexp == fopexp) /* compare exponents */
|
if (facexp == fopexp) /* compare exponents */
|
||||||
if (templl == fop) { /* compare fractions */
|
if (templl == fop) { /* compare fractions */
|
||||||
TRACE(T_FP, " dfcs: frac cmp returning eq / skip 1\n");
|
|
||||||
SETEQ;
|
SETEQ;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (templl < fop) { /* compare fractions */
|
} else if (templl < fop) { /* compare fractions */
|
||||||
TRACE(T_FP, " dfcs: frac cmp returning lt / skip 2\n");
|
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else
|
||||||
TRACE(T_FP, " dfcs: frac cmp returning gt / skip 0\n");
|
|
||||||
return 0; /* FAC > operand */
|
return 0; /* FAC > operand */
|
||||||
}
|
|
||||||
else if (facexp < fopexp) { /* compare exponents */
|
else if (facexp < fopexp) { /* compare exponents */
|
||||||
TRACE(T_FP, " dfcs: exp cmp returning lt / skip 2\n");
|
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else
|
||||||
TRACE(T_FP, " dfcs: exp cmp returning eq / skip 1\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
} else if (templl & 0x8000000000000000LL) {
|
} else if (templl & 0x8000000000000000LL) {
|
||||||
TRACE(T_FP, " dfcs: sign cmp returning lt / skip 2\n");
|
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else
|
||||||
TRACE(T_FP, " dfcs: sign cmp returning gt / skip 0\n");
|
|
||||||
return 0; /* FAC > operand */
|
return 0; /* FAC > operand */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
16
makefile
16
makefile
@@ -7,29 +7,25 @@ all_deps = makefile
|
|||||||
em_objs = em.o em
|
em_objs = em.o em
|
||||||
em_deps = \
|
em_deps = \
|
||||||
em.c regs.h emdev.h ea64v.h ea32i.h fp.h dispatch.h geom.h \
|
em.c regs.h emdev.h ea64v.h ea32i.h fp.h dispatch.h geom.h \
|
||||||
devpnc.h devamlc.h devsmlc.h swap.h
|
devpnc.h devamlc.h swap.h
|
||||||
|
|
||||||
CFLAGS =
|
|
||||||
# Uncomment for building on SmartOS/Solaris:
|
|
||||||
# CFLAGS += -lsocket -lnsl
|
|
||||||
|
|
||||||
.PHONY: emwarn debug trace fixed
|
.PHONY: emwarn debug trace fixed
|
||||||
|
|
||||||
# normal
|
# normal
|
||||||
em: $(em_deps) $(all_deps)
|
em: $(em_deps) $(all_deps)
|
||||||
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DNOTRACE -DFAST -O -Winline -Wno-return-type em.c -o em
|
$(CC) -DREV=\"${REV}\" -DNOTRACE -DFAST -O -Winline -Wno-return-type em.c -o em
|
||||||
|
|
||||||
# lots of compiler warnings
|
# lots of compiler warnings
|
||||||
emwarn: $(em_deps) $(all_deps)
|
emwarn: $(em_deps) $(all_deps)
|
||||||
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DNOTRACE -DFAST -O -Wall -Wextra -pedantic -Wconversion em.c -o em
|
$(CC) -DREV=\"${REV}\" -DNOTRACE -DFAST -O -Wall -Wextra -pedantic -Wconversion em.c -o em
|
||||||
|
|
||||||
# gdb
|
# gdb
|
||||||
debug: $(em_deps) $(all_deps)
|
debug: $(em_deps) $(all_deps)
|
||||||
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DNOTRACE -DFAST -g -O0 em.c -o em
|
$(CC) -DREV=\"${REV}\" -DNOTRACE -DFAST -g -O0 em.c -o em
|
||||||
|
|
||||||
# tracing
|
# tracing
|
||||||
trace: $(em_deps) $(all_deps)
|
trace: $(em_deps) $(all_deps)
|
||||||
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DFAST -O em.c -o em
|
$(CC) -DREV=\"${REV}\" -DFAST -O em.c -o em
|
||||||
|
|
||||||
# the fixed clock rate build is useful for making problems reproduceable.
|
# the fixed clock rate build is useful for making problems reproduceable.
|
||||||
#
|
#
|
||||||
@@ -39,7 +35,7 @@ trace: $(em_deps) $(all_deps)
|
|||||||
|
|
||||||
# fixed clock rate
|
# fixed clock rate
|
||||||
fixed: $(em_deps) $(all_deps)
|
fixed: $(em_deps) $(all_deps)
|
||||||
$(CC) -DREV=\"${REV}\" ${CFLAGS} -DFIXEDCLOCK -DNOIDLE -DFAST -O em.c -o em
|
$(CC) -DREV=\"${REV}\" -DFIXEDCLOCK -DNOIDLE -DFAST -O em.c -o em
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(em_objs)
|
rm -f $(em_objs)
|
||||||
|
|||||||
5
regs.h
5
regs.h
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#define REGSETS 10
|
#define REGSETS 10
|
||||||
|
|
||||||
|
#define T_REGS 0x00100000
|
||||||
|
|
||||||
/* these are 16-bit absolute offsets into the register file */
|
/* these are 16-bit absolute offsets into the register file */
|
||||||
|
|
||||||
#define PSWKEYS16 031*2
|
#define PSWKEYS16 031*2
|
||||||
@@ -292,6 +294,7 @@ static inline uint16_t getcrs16(int offset) { \
|
|||||||
/* store 16-bit unsigned at 16-bit offset */
|
/* store 16-bit unsigned at 16-bit offset */
|
||||||
//#define putcrs16(offset, val) crs[(offset)] = (val)
|
//#define putcrs16(offset, val) crs[(offset)] = (val)
|
||||||
static inline void putcrs16(int offset, uint16_t 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); \
|
crs[(offset)] = swap16(val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,6 +315,7 @@ static inline uint32_t getcrs32(int offset) { \
|
|||||||
/* put 32-bit unsigned at 16-bit offset */
|
/* put 32-bit unsigned at 16-bit offset */
|
||||||
//#define putcrs32(offset, val) *(unsigned int *)(crs+(offset)) = (val)
|
//#define putcrs32(offset, val) *(unsigned int *)(crs+(offset)) = (val)
|
||||||
static inline void putcrs32(int offset, uint32_t 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); \
|
*(unsigned int *)(crs+offset) = swap32(val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,6 +356,7 @@ static inline uint16_t getar16(int offset) { \
|
|||||||
|
|
||||||
/* put 16-bit unsigned at 16-bit absolute register file address */
|
/* put 16-bit unsigned at 16-bit absolute register file address */
|
||||||
static inline void putar16(int offset, uint16_t val) { \
|
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); \
|
regs.u16[(offset)] = swap16(val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
util/cmraw.c
35
util/cmraw.c
@@ -1,35 +0,0 @@
|
|||||||
/* 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);
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,7 @@ main () {
|
|||||||
else { /* not a space character */
|
else { /* not a space character */
|
||||||
while (space) { /* dump held-back spaces first */
|
while (space) { /* dump held-back spaces first */
|
||||||
if (space < 3) { /* write regular spaces */
|
if (space < 3) { /* write regular spaces */
|
||||||
putchar(0240);
|
putchar(' ');
|
||||||
space--;
|
space--;
|
||||||
n++;
|
n++;
|
||||||
} else { /* write compressed spaces */
|
} else { /* write compressed spaces */
|
||||||
|
|||||||
Reference in New Issue
Block a user