1
0
mirror of https://github.com/prirun/p50em.git synced 2026-03-24 08:59:37 +00:00

1 Commits

Author SHA1 Message Date
Dennis Boone
2458dd7c2e Add T_REGS trace type. 2020-04-17 22:17:01 -04:00
20 changed files with 2646 additions and 4277 deletions

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

1292
devsmlc.h

File diff suppressed because it is too large Load Diff

33
em.1
View File

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

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

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

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

View File

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

@@ -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); \
} }

View File

@@ -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);
}

View File

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