1
0
mirror of https://github.com/prirun/p50em.git synced 2026-03-04 18:14:16 +00:00

13 Commits

Author SHA1 Message Date
Dennis Boone
e61857e333 Man page enhancements
Credit Kevin Jordan for sync serial support.

Add smlc.cfg info.

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

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

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

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

Output on x86-64 before this change:

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

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

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

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

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

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

1
.gitignore vendored
View File

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

1284
devamlc.h

File diff suppressed because it is too large Load Diff

216
devpnc.h
View File

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

1234
devsmlc.h Normal file

File diff suppressed because it is too large Load Diff

28
ea32i.h
View File

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

32
ea64v.h
View File

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

21
em.1
View File

@@ -2,7 +2,7 @@
.\" em.1, Boone, 03/13/20
.\" Man page for Jim Wilcoxson's Prime 50-Series emulator
.\" ---------------------------------------------------------------------------
.TH em 1 "2020-03-14" "Jim Wilcoxson" "50-Series Emulator"
.TH em 1 "2020-06-23" "Jim Wilcoxson" "50-Series Emulator"
.\" ---------------------------------------------------------------------------
.SH NAME
em \- Emulator for Prime 50-Series systems
@@ -35,6 +35,8 @@ a tape controller, 4 drives, using the .TAP format
.IP \(bu
a PNC controller emulating RingNet over TCP/IP
.IP \(bu
two sync serial controllers supporting up to 8 lines
.IP \(bu
a bypass for Primos system serial number checks
.IP \(bu
Unix utilities to read/write physical tapes & Magsav tapes
@@ -163,6 +165,16 @@ Example:
8 192.168.10.4:9000 # Outbound socket connection e.g. for spooler
.EE
.TP
smlc.cfg
Used to associate sync serial (MDLC or HSSMLC) lines with a destination
IP address and port number. Optional. Comments work the same as
amlc.cfg. Example:
.EX
0 10.1.1.3:2554
1 127.0.0.1:2554
.EE
.TP
console.log
All console output is also written to this file. It is overwritten
at each invocation. Created by
@@ -275,8 +287,10 @@ all|Everything
flush|Flush trace file after each write
tlb|STLB and IOTLB changes
OWNERL|Execution of this PCB
instruction count|Begin after specified number of instructions
#instruction count|Begin after specified number of instructions
|(the leading # is literal)
octal segno|Execution in the given segment number
|(may interact poorly with "off")
process number|Execution of this user number
.TE
.\" ---------------------------------------------------------------------------
@@ -360,7 +374,8 @@ CMD,1/3/5+1,Cartridge Module 32/64/96 MB
.\" ---------------------------------------------------------------------------
.SH AUTHOR
.PP
This emulator was written by Jim Wilcoxson. Man page by Dennis Boone.
This emulator was written by Jim Wilcoxson. MDLC/HSSMLC support by
Kevin Jordan. Man page by Dennis Boone.
.\" ---------------------------------------------------------------------------
.SH SEE ALSO
This project is hosted at

1521
em.c

File diff suppressed because it is too large Load Diff

1290
emdev.h

File diff suppressed because it is too large Load Diff

40
fp.h
View File

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

View File

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

96
regs.h
View File

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

35
util/cmraw.c Normal file
View File

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