mirror of
https://github.com/prirun/p50em.git
synced 2026-03-04 18:14:16 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e61857e333 | ||
|
|
4771f09e1e | ||
|
|
6bf6e2ea48 | ||
|
|
edf7129651 | ||
|
|
543aa3f963 | ||
|
|
7d7504a02e | ||
|
|
43d2d863d7 | ||
|
|
80c1a57895 | ||
|
|
d566f42ea6 | ||
|
|
af1718f699 | ||
|
|
91bddd02c3 | ||
|
|
4def8fe397 | ||
|
|
43bbf3cd8f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
|||||||
*.log
|
*.log
|
||||||
*.swp
|
*.swp
|
||||||
tags
|
tags
|
||||||
|
cmraw
|
||||||
cscope.*
|
cscope.*
|
||||||
em
|
em
|
||||||
emlink
|
emlink
|
||||||
|
|||||||
216
devpnc.h
216
devpnc.h
@@ -77,7 +77,7 @@
|
|||||||
1: "Type" word.
|
1: "Type" word.
|
||||||
Bit 1 set = odd number of bytes (if set, last word is only 1 byte)
|
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 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
|
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.
|
with a ring packet on the wire, for example, a CRC, ack byte, etc.
|
||||||
@@ -121,15 +121,15 @@
|
|||||||
7: data 2
|
7: data 2
|
||||||
|
|
||||||
PNC diagnostic register:
|
PNC diagnostic register:
|
||||||
NORXTX EQU '100000 DISABLE TX AND RX
|
NORXTX EQU '100000 DISABLE TX AND RX
|
||||||
TXDATER EQU '040000 FORCE RX CRC ERROR
|
TXDATER EQU '040000 FORCE RX CRC ERROR
|
||||||
TXACKER EQU '020000 FORCE TX ACK ERROR
|
TXACKER EQU '020000 FORCE TX ACK ERROR
|
||||||
RXACKER EQU '010000 FORCE RX ACK BYTE ERROR
|
RXACKER EQU '010000 FORCE RX ACK BYTE ERROR
|
||||||
CABLE EQU '000001 LOOPBACK OVER CABLE
|
CABLE EQU '000001 LOOPBACK OVER CABLE
|
||||||
ANALOG EQU '000002 LOOPBACK THRU ANALOG DEVICES
|
ANALOG EQU '000002 LOOPBACK THRU ANALOG DEVICES
|
||||||
SINGSTEP EQU '000004 LOOPBACK THRU SHIFT REG
|
SINGSTEP EQU '000004 LOOPBACK THRU SHIFT REG
|
||||||
RETRY EQU '000000 ALLOW HARDWR RETRY
|
RETRY EQU '000000 ALLOW HARDWR RETRY
|
||||||
NORETRY EQU '000010 NO HARDWR RETRY
|
NORETRY EQU '000010 NO HARDWR RETRY
|
||||||
|
|
||||||
Primos PNC usage:
|
Primos PNC usage:
|
||||||
|
|
||||||
@@ -439,7 +439,7 @@ void pncaccept(time_t timenow) {
|
|||||||
fd = accept(pncfd, (struct sockaddr *)&addr, &addrlen);
|
fd = accept(pncfd, (struct sockaddr *)&addr, &addrlen);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
if (errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN)
|
if (errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN)
|
||||||
perror("accept error for PNC");
|
perror("accept error for PNC");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(pncstat & PNCNSCONNECTED)) {
|
if (!(pncstat & PNCNSCONNECTED)) {
|
||||||
@@ -731,7 +731,7 @@ unsigned short pncxmit() {
|
|||||||
if (xmit.toid == 255) {
|
if (xmit.toid == 255) {
|
||||||
for (nodeid=1; nodeid<=MAXNODEID; nodeid++)
|
for (nodeid=1; nodeid<=MAXNODEID; nodeid++)
|
||||||
if (ni[nodeid].cstate != PNCCSNONE)
|
if (ni[nodeid].cstate != PNCCSNONE)
|
||||||
xmitstat |= pncxmit1(nodeid);
|
xmitstat |= pncxmit1(nodeid);
|
||||||
} else {
|
} else {
|
||||||
xmitstat |= pncxmit1(xmit.toid);
|
xmitstat |= pncxmit1(xmit.toid);
|
||||||
}
|
}
|
||||||
@@ -764,7 +764,7 @@ void pncrecv() {
|
|||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
FD_SET(fd, &fds);
|
FD_SET(fd, &fds);
|
||||||
if (fd > n)
|
if (fd > n)
|
||||||
n = fd;
|
n = fd;
|
||||||
}
|
}
|
||||||
n = select(n+1, &fds, NULL, NULL, &timeout);
|
n = select(n+1, &fds, NULL, NULL, &timeout);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
@@ -784,7 +784,7 @@ void pncrecv() {
|
|||||||
fd = ni[nodeid].fd;
|
fd = ni[nodeid].fd;
|
||||||
if (fd >= 0 && FD_ISSET(fd, &fds))
|
if (fd >= 0 && FD_ISSET(fd, &fds))
|
||||||
if (pncrecv1(nodeid))
|
if (pncrecv1(nodeid))
|
||||||
break;
|
break;
|
||||||
} while (nodeid != prevnode); /* went round once? */
|
} while (nodeid != prevnode); /* went round once? */
|
||||||
prevnode = nodeid;
|
prevnode = nodeid;
|
||||||
}
|
}
|
||||||
@@ -853,7 +853,7 @@ int pncread (int nodeid, int nbytes) {
|
|||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN) {
|
if (errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN) {
|
||||||
if (errno != EPIPE)
|
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");
|
pncdisc(nodeid, "error reading packet");
|
||||||
}
|
}
|
||||||
n = 0;
|
n = 0;
|
||||||
@@ -925,92 +925,92 @@ int devpnc (int class, int func, int device) {
|
|||||||
where:
|
where:
|
||||||
nodeid = node's id (1-247) on my ring
|
nodeid = node's id (1-247) on my ring
|
||||||
host = the remote emulator's TCP/IP address or name
|
host = the remote emulator's TCP/IP address or name
|
||||||
port = the remote emulator's TCP/IP PNC port
|
port = the remote emulator's TCP/IP PNC port
|
||||||
NOTE: host:port may be - for incoming-only nodes
|
NOTE: host:port may be - for incoming-only nodes
|
||||||
uid = 16 byte password, no spaces
|
uid = 16 byte password, no spaces
|
||||||
NOTE: use od -h /dev/urandom|head to create a uid
|
NOTE: use od -h /dev/urandom|head to create a uid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
linenum = 0;
|
linenum = 0;
|
||||||
if ((ringfile=fopen("ring.cfg", "r")) != NULL) {
|
if ((ringfile=fopen("ring.cfg", "r")) != NULL) {
|
||||||
while (fgets(buf, sizeof(buf), ringfile) != NULL) {
|
while (fgets(buf, sizeof(buf), ringfile) != NULL) {
|
||||||
len = strlen(buf);
|
len = strlen(buf);
|
||||||
linenum++;
|
linenum++;
|
||||||
if (buf[len-1] != '\n') {
|
if (buf[len-1] != '\n') {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: line too long, can't parse file\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: line too long, can't parse file\n", linenum);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buf[len-1] = 0;
|
buf[len-1] = 0;
|
||||||
if (strcmp(buf,"") == 0 || buf[0] == ';' || buf[0] == '#')
|
if (strcmp(buf,"") == 0 || buf[0] == ';' || buf[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((p=strtok(buf, DELIM)) == NULL) {
|
if ((p=strtok(buf, DELIM)) == NULL) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: node id missing\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: node id missing\n", linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tempid = atoi(p);
|
tempid = atoi(p);
|
||||||
if (tempid < 1 || tempid > MAXNODEID) {
|
if (tempid < 1 || tempid > MAXNODEID) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: node id is out of range 1-%d\n", linenum, MAXNODEID);
|
fprintf(stderr,"Line %d of ring.cfg ignored: node id is out of range 1-%d\n", linenum, MAXNODEID);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ni[tempid].cstate != PNCCSNONE) {
|
if (ni[tempid].cstate != PNCCSNONE) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: node id occurs more than once\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: node id occurs more than once\n", linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((p=strtok(NULL, DELIM)) == NULL) {
|
if ((p=strtok(NULL, DELIM)) == NULL) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: host address missing\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: host address missing\n", linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strlen(p) > MAXHOSTLEN) {
|
if (strlen(p) > MAXHOSTLEN) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: IP address too long\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: IP address too long\n", linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
strncpy(temphost, p, MAXHOSTLEN);
|
strncpy(temphost, p, MAXHOSTLEN);
|
||||||
|
|
||||||
if ((p=strtok(NULL, DELIM)) == NULL) {
|
if ((p=strtok(NULL, DELIM)) == NULL) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password missing\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password missing\n", linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strlen(p) > MAXUIDLEN) {
|
if (strlen(p) > MAXUIDLEN) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password too long\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password too long\n", linenum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bzero(ni[tempid].uid, sizeof(ni[tempid].uid));
|
bzero(ni[tempid].uid, sizeof(ni[tempid].uid));
|
||||||
for (i=0; i<=MAXNODEID; i++)
|
for (i=0; i<=MAXNODEID; i++)
|
||||||
if (strcmp(p, ni[i].uid) == 0) {
|
if (strcmp(p, ni[i].uid) == 0) {
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password is not unique\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: unique id/password is not unique\n", linenum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i <= MAXNODEID)
|
if (i <= MAXNODEID)
|
||||||
continue;
|
continue;
|
||||||
strncpy(ni[tempid].uid, p, MAXUIDLEN);
|
strncpy(ni[tempid].uid, p, MAXUIDLEN);
|
||||||
|
|
||||||
/* parse the port number from the IP address */
|
/* parse the port number from the IP address */
|
||||||
|
|
||||||
tempport = 0;
|
tempport = 0;
|
||||||
if (strcmp(temphost, "-") != 0) {
|
if (strcmp(temphost, "-") != 0) {
|
||||||
if ((p=strtok(temphost, PDELIM)) != NULL) {
|
if ((p=strtok(temphost, PDELIM)) != NULL) {
|
||||||
strncpy(ni[tempid].host, p, MAXHOSTLEN);
|
strncpy(ni[tempid].host, p, MAXHOSTLEN);
|
||||||
if ((p=strtok(NULL, PDELIM)) != NULL) {
|
if ((p=strtok(NULL, PDELIM)) != NULL) {
|
||||||
tempport = atoi(p);
|
tempport = atoi(p);
|
||||||
if (tempport < 1 || tempport > 65000)
|
if (tempport < 1 || tempport > 65000)
|
||||||
fprintf(stderr,"Line %d of ring.cfg ignored: port number out of range 1-65000\n", linenum);
|
fprintf(stderr,"Line %d of ring.cfg ignored: port number out of range 1-65000\n", linenum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tempport <= 0) {
|
if (tempport <= 0) {
|
||||||
fprintf(stderr, "Line %d of ring.cfg ignored: can't parse port number from %s\n", linenum, temphost);
|
fprintf(stderr, "Line %d of ring.cfg ignored: can't parse port number from %s\n", linenum, temphost);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ni[tempid].cstate = PNCCSDISC;
|
ni[tempid].cstate = PNCCSDISC;
|
||||||
ni[tempid].port = tempport;
|
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);
|
TRACE(T_RIO, "Line %d: id=%d, host=\"%s\", port=%d, uid=%s\n", linenum, tempid, temphost, tempport, ni[tempid].uid);
|
||||||
configured = 1;
|
configured = 1;
|
||||||
}
|
}
|
||||||
if (!feof(ringfile)) {
|
if (!feof(ringfile)) {
|
||||||
perror(" error reading ring.cfg");
|
perror(" error reading ring.cfg");
|
||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
}
|
}
|
||||||
fclose(ringfile);
|
fclose(ringfile);
|
||||||
} else
|
} else
|
||||||
@@ -1087,7 +1087,7 @@ int devpnc (int class, int func, int device) {
|
|||||||
if (func == 00) { /* OCP '0007 - disconnect */
|
if (func == 00) { /* OCP '0007 - disconnect */
|
||||||
TRACE(T_INST|T_RIO, " OCP '%02o%02o - disconnect\n", func, device);
|
TRACE(T_INST|T_RIO, " OCP '%02o%02o - disconnect\n", func, device);
|
||||||
for (i=0; i<=MAXNODEID; i++)
|
for (i=0; i<=MAXNODEID; i++)
|
||||||
pncdisc(i, "ring disconnect");
|
pncdisc(i, "ring disconnect");
|
||||||
rcv.state = PNCBSIDLE;
|
rcv.state = PNCBSIDLE;
|
||||||
rcvstat = PNCRSBUSY;
|
rcvstat = PNCRSBUSY;
|
||||||
xmitstat = PNCXSBUSY;
|
xmitstat = PNCXSBUSY;
|
||||||
@@ -1183,12 +1183,12 @@ int devpnc (int class, int func, int device) {
|
|||||||
IOSKIP;
|
IOSKIP;
|
||||||
|
|
||||||
/* these next two are mostly bogus: prmnt1 T&M wants them this
|
/* these next two are mostly bogus: prmnt1 T&M wants them this
|
||||||
way because it puts the PNC in diagnostic mode, disables
|
way because it puts the PNC in diagnostic mode, disables
|
||||||
transmit and receive, then does transmit and receive
|
transmit and receive, then does transmit and receive
|
||||||
operations to see how the DMA registers are affected. I
|
operations to see how the DMA registers are affected. I
|
||||||
couldn't get very far with this T&M (couldn't complete test
|
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
|
1) because it is so specific to the exact states the PNC
|
||||||
hardware moves through. */
|
hardware moves through. */
|
||||||
|
|
||||||
} else if (func == 014) { /* read recv DMX channel */
|
} 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);
|
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 */
|
} else if (func == 014) { /* initiate recv, dma chan in A */
|
||||||
if (!(pncstat & PNCNSCONNECTED)) {
|
if (!(pncstat & PNCNSCONNECTED)) {
|
||||||
break; /* yes, return and don't skip */
|
break; /* yes, return and don't skip */
|
||||||
}
|
}
|
||||||
if (rcvstat & PNCRSBUSY) { /* already busy? */
|
if (rcvstat & PNCRSBUSY) { /* already busy? */
|
||||||
warn("pnc: recv when already busy ignored");
|
warn("pnc: recv when already busy ignored");
|
||||||
break; /* yes, return and don't skip */
|
break; /* yes, return and don't skip */
|
||||||
}
|
}
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
rcvstat = PNCRSBUSY; /* set receive busy */
|
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 */
|
} else if (func == 015) { /* initiate xmit, dma chan in A */
|
||||||
if (!(pncstat & PNCNSCONNECTED)) {
|
if (!(pncstat & PNCNSCONNECTED)) {
|
||||||
break; /* yes, return and don't skip */
|
break; /* yes, return and don't skip */
|
||||||
}
|
}
|
||||||
if (xmitstat & PNCXSBUSY) { /* already busy? */
|
if (xmitstat & PNCXSBUSY) { /* already busy? */
|
||||||
warn("pnc: xmit when already busy ignored");
|
warn("pnc: xmit when already busy ignored");
|
||||||
break; /* yes, return and don't skip */
|
break; /* yes, return and don't skip */
|
||||||
}
|
}
|
||||||
IOSKIP;
|
IOSKIP;
|
||||||
pncxmit();
|
pncxmit();
|
||||||
@@ -1259,12 +1259,12 @@ int devpnc (int class, int func, int device) {
|
|||||||
} else if (func == 017) { /* set my node ID */
|
} else if (func == 017) { /* set my node ID */
|
||||||
myid = getcrs16(A) & 0xFF;
|
myid = getcrs16(A) & 0xFF;
|
||||||
if (myid > MAXNODEID) {
|
if (myid > MAXNODEID) {
|
||||||
printf("em: my nodeid %d > max nodeid %d; check Primenet config\n", myid, MAXNODEID);
|
printf("em: my nodeid %d > max nodeid %d; check Primenet config\n", myid, MAXNODEID);
|
||||||
myid = 0;
|
myid = 0;
|
||||||
}
|
}
|
||||||
if (myid != 0 && ni[myid].cstate == PNCCSNONE) {
|
if (myid != 0 && ni[myid].cstate == PNCCSNONE) {
|
||||||
printf("em: my nodeid %d not in ring.cfg; PNC disabled\n", myid);
|
printf("em: my nodeid %d not in ring.cfg; PNC disabled\n", myid);
|
||||||
myid = 0;
|
myid = 0;
|
||||||
}
|
}
|
||||||
pncstat = (pncstat & 0xFF00) | myid;
|
pncstat = (pncstat & 0xFF00) | myid;
|
||||||
ni[myid].cstate = PNCCSAUTH;
|
ni[myid].cstate = PNCCSAUTH;
|
||||||
@@ -1303,10 +1303,10 @@ rcvexit:
|
|||||||
intrexit:
|
intrexit:
|
||||||
if (enabled && ((pncstat & 0xC000) | intstat) != intstat) {
|
if (enabled && ((pncstat & 0xC000) | intstat) != intstat) {
|
||||||
if (gv.intvec == -1) {
|
if (gv.intvec == -1) {
|
||||||
gv.intvec = pncvec;
|
gv.intvec = pncvec;
|
||||||
intstat |= (pncstat & 0xC000);
|
intstat |= (pncstat & 0xC000);
|
||||||
} else
|
} else
|
||||||
devpoll[device] = 100;
|
devpoll[device] = 100;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
28
ea32i.h
28
ea32i.h
@@ -26,33 +26,33 @@ static inline ea_t ea32i (ea_t earp, unsigned short inst, unsigned int *immu32,
|
|||||||
d = iget16(RP);
|
d = iget16(RP);
|
||||||
RPL++;
|
RPL++;
|
||||||
if (sr == 0) /* imm type 1 */
|
if (sr == 0) /* imm type 1 */
|
||||||
*immu32 = d << 16;
|
*immu32 = d << 16;
|
||||||
else /* imm type 2 */
|
else /* imm type 2 */
|
||||||
*(int *)immu32 = *(short *)&d;
|
*(int *)immu32 = *(short *)&d;
|
||||||
return IMM_EA;
|
return IMM_EA;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
switch (sr) {
|
switch (sr) {
|
||||||
case 0: /* imm type 3 */
|
case 0: /* imm type 3 */
|
||||||
d = iget16(RP);
|
d = iget16(RP);
|
||||||
INCRP;
|
INCRP;
|
||||||
*immu64 = (((long long)(d & 0xFF00)) << 48) | (d & 0xFF);
|
*immu64 = (((long long)(d & 0xFF00)) << 48) | (d & 0xFF);
|
||||||
return IMM_EA;
|
return IMM_EA;
|
||||||
case 1: /* FAC0 source */
|
case 1: /* FAC0 source */
|
||||||
*immu64 = getgr64(FAC0);
|
*immu64 = getgr64(FAC0);
|
||||||
return IMM_EA;
|
return IMM_EA;
|
||||||
case 3: /* FAC1 source */
|
case 3: /* FAC1 source */
|
||||||
*immu64 = getgr64(FAC1);
|
*immu64 = getgr64(FAC1);
|
||||||
return IMM_EA;
|
return IMM_EA;
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
fault(UIIFAULT, RPL, RP);
|
fault(UIIFAULT, RPL, RP);
|
||||||
fatal("ea32i: return from UII fault!");
|
fatal("ea32i: return from UII fault!");
|
||||||
default:
|
default:
|
||||||
fatal("ea32i: sr < 0 or > 7?");
|
fatal("ea32i: sr < 0 or > 7?");
|
||||||
}
|
}
|
||||||
fatal("ea32i: case tm=0 br=2 fall-through");
|
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);
|
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);
|
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)
|
if (ea & 0x80000000)
|
||||||
fault(POINTERFAULT, ea>>16, ea);
|
fault(POINTERFAULT, ea>>16, ea);
|
||||||
return ea | ring;
|
return ea | ring;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
32
ea64v.h
32
ea64v.h
@@ -55,18 +55,18 @@ static inline ea_t ea64v (unsigned short inst, ea_t earp) {
|
|||||||
|
|
||||||
if (xok)
|
if (xok)
|
||||||
if (ixy == 2 || ixy == 6)
|
if (ixy == 2 || ixy == 6)
|
||||||
ea_w += getcrs16(X);
|
ea_w += getcrs16(X);
|
||||||
else if (ixy == 1 || ixy == 4)
|
else if (ixy == 1 || ixy == 4)
|
||||||
ea_w += getcrs16(Y);
|
ea_w += getcrs16(Y);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* if this is a PB% address, use RPBR instead if it's in range
|
/* if this is a PB% address, use RPBR instead if it's in range
|
||||||
|
|
||||||
NOTE: this has been disabled, because gcov showed it only
|
NOTE: this has been disabled, because gcov showed it only
|
||||||
occurred 0.5% of the time */
|
occurred 0.5% of the time */
|
||||||
|
|
||||||
if (br == 0 && ((((ea_s & 0x8FFF) << 16) | (ea_w & 0xFC00)) == gv.brp[RPBR].vpn))
|
if (br == 0 && ((((ea_s & 0x8FFF) << 16) | (ea_w & 0xFC00)) == gv.brp[RPBR].vpn))
|
||||||
eap = &gv.brp[RPBR];
|
eap = &gv.brp[RPBR];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ixy >= 3) {
|
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);
|
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);
|
m = get16(ea);
|
||||||
if (m & 0x8000)
|
if (m & 0x8000)
|
||||||
fault(POINTERFAULT, m, ea);
|
fault(POINTERFAULT, m, ea);
|
||||||
ea_s = m | (ea_s & RINGMASK16);
|
ea_s = m | (ea_s & RINGMASK16);
|
||||||
ea_w = get16(INCVA(ea,1));
|
ea_w = get16(INCVA(ea,1));
|
||||||
TRACE(T_EAV, " After indirect, ea_s=%o, ea_w=%o\n", ea_s, ea_w);
|
TRACE(T_EAV, " After indirect, ea_s=%o, ea_w=%o\n", ea_s, ea_w);
|
||||||
|
|
||||||
/* when passing stack variables, callee references will be
|
/* when passing stack variables, callee references will be
|
||||||
SB%+20,*, which may still be in the same page. Don't switch to
|
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 */
|
UNBR if the new ea is still in the current page */
|
||||||
|
|
||||||
if ((((ea_s & 0x8FFF) << 16) | (ea_w & 0xFC00)) != (eap->vpn & 0x0FFFFFFF))
|
if ((((ea_s & 0x8FFF) << 16) | (ea_w & 0xFC00)) != (eap->vpn & 0x0FFFFFFF))
|
||||||
eap = &gv.brp[UNBR];
|
eap = &gv.brp[UNBR];
|
||||||
|
|
||||||
if (xok)
|
if (xok)
|
||||||
if (ixy == 7) {
|
if (ixy == 7) {
|
||||||
TRACE(T_EAV, " Postindex, old ea_w=%o, X='%o/%d\n", ea_w, getcrs16(X), getcrs16s(X));
|
TRACE(T_EAV, " Postindex, old ea_w=%o, X='%o/%d\n", ea_w, getcrs16(X), getcrs16s(X));
|
||||||
ea_w += getcrs16(X);
|
ea_w += getcrs16(X);
|
||||||
} else if (ixy == 5) {
|
} else if (ixy == 5) {
|
||||||
TRACE(T_EAV, " Postindex, old ea_w=%o, Y='%o/%d\n", ea_w, getcrs16(Y), getcrs16s(Y));
|
TRACE(T_EAV, " Postindex, old ea_w=%o, Y='%o/%d\n", ea_w, getcrs16(Y), getcrs16s(Y));
|
||||||
ea_w += getcrs16(Y);
|
ea_w += getcrs16(Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MAKEVA(ea_s, ea_w);
|
return MAKEVA(ea_s, ea_w);
|
||||||
}
|
}
|
||||||
|
|||||||
21
em.1
21
em.1
@@ -2,7 +2,7 @@
|
|||||||
.\" em.1, Boone, 03/13/20
|
.\" em.1, Boone, 03/13/20
|
||||||
.\" Man page for Jim Wilcoxson's Prime 50-Series emulator
|
.\" Man page for Jim Wilcoxson's Prime 50-Series emulator
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.TH em 1 "2020-03-14" "Jim Wilcoxson" "50-Series Emulator"
|
.TH em 1 "2020-06-23" "Jim Wilcoxson" "50-Series Emulator"
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH NAME
|
.SH NAME
|
||||||
em \- Emulator for Prime 50-Series systems
|
em \- Emulator for Prime 50-Series systems
|
||||||
@@ -35,6 +35,8 @@ 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
|
||||||
@@ -163,6 +165,16 @@ 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 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
|
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
|
||||||
@@ -275,8 +287,10 @@ 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
|
||||||
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
|
||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
@@ -360,7 +374,8 @@ CMD,1/3/5+1,Cartridge Module 32/64/96 MB
|
|||||||
.\" ---------------------------------------------------------------------------
|
.\" ---------------------------------------------------------------------------
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.PP
|
.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
|
.SH SEE ALSO
|
||||||
This project is hosted at
|
This project is hosted at
|
||||||
|
|||||||
40
fp.h
40
fp.h
@@ -70,7 +70,7 @@ int prieee8(unsigned long long dp, double *d) {
|
|||||||
if (frac64 == 0x8000000000000000LL) {
|
if (frac64 == 0x8000000000000000LL) {
|
||||||
exp32 += (1023-128);
|
exp32 += (1023-128);
|
||||||
if (exp32 < 0 || exp32 > 0x7fe)
|
if (exp32 < 0 || exp32 > 0x7fe)
|
||||||
return 0;
|
return 0;
|
||||||
frac64 |= ((long long)exp32 << 52);
|
frac64 |= ((long long)exp32 << 52);
|
||||||
*d = *(double *)&frac64;
|
*d = *(double *)&frac64;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -142,11 +142,11 @@ retry:
|
|||||||
okay = 0;
|
okay = 0;
|
||||||
if (frac64 == 0)
|
if (frac64 == 0)
|
||||||
if (neg) {
|
if (neg) {
|
||||||
printf("em: +infinity in ieeepr8\n");
|
printf("em: +infinity in ieeepr8\n");
|
||||||
d = DBL_MAX;
|
d = DBL_MAX;
|
||||||
} else {
|
} else {
|
||||||
printf("em: -infinity in ieeepr8\n");
|
printf("em: -infinity in ieeepr8\n");
|
||||||
d = DBL_MIN;
|
d = DBL_MIN;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("em: NaN in ieeepr8\n");
|
printf("em: NaN in ieeepr8\n");
|
||||||
@@ -267,8 +267,8 @@ unsigned long long dfcm (unsigned long long dp, int *oflow) {
|
|||||||
} else {
|
} else {
|
||||||
frac64 = -frac64; /* complement fraction */
|
frac64 = -frac64; /* complement fraction */
|
||||||
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
while ((frac64 ^ (frac64 << 1)) >= 0) {
|
||||||
frac64 = frac64 << 1; /* normalize */
|
frac64 = frac64 << 1; /* normalize */
|
||||||
exp32--;
|
exp32--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exp32 > 32767 || exp32 < -32768)
|
if (exp32 > 32767 || exp32 < -32768)
|
||||||
@@ -322,10 +322,10 @@ unsigned long long frn(unsigned long long dp, int *oflow) {
|
|||||||
if (doround1 || doround2) {
|
if (doround1 || doround2) {
|
||||||
frac64 &= 0xFFFFFF0000000000LL;
|
frac64 &= 0xFFFFFF0000000000LL;
|
||||||
if (frac64 != 0x7FFFFF0000000000LL)
|
if (frac64 != 0x7FFFFF0000000000LL)
|
||||||
frac64 += 0x10000000000LL;
|
frac64 += 0x10000000000LL;
|
||||||
else {
|
else {
|
||||||
frac64 = 0x4000000000000000LL;
|
frac64 = 0x4000000000000000LL;
|
||||||
exp32++;
|
exp32++;
|
||||||
}
|
}
|
||||||
frac64 |= (exp32 & 0xFFFF);
|
frac64 |= (exp32 & 0xFFFF);
|
||||||
frac64 = norm(frac64, oflow);
|
frac64 = norm(frac64, oflow);
|
||||||
@@ -359,13 +359,13 @@ int fcs (unsigned long long fac, int fop) {
|
|||||||
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 */
|
||||||
SETEQ;
|
SETEQ;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (templ < fop) { /* compare fractions */
|
} else if (templ < fop) { /* compare fractions */
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else
|
} else
|
||||||
return 0; /* FAC > operand */
|
return 0; /* FAC > operand */
|
||||||
else if (facexp < fopexp) { /* compare exponents */
|
else if (facexp < fopexp) { /* compare exponents */
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
@@ -410,13 +410,13 @@ int dfcs (unsigned long long fac, long long fop) {
|
|||||||
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 */
|
||||||
SETEQ;
|
SETEQ;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (templl < fop) { /* compare fractions */
|
} else if (templl < fop) { /* compare fractions */
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
} else
|
} else
|
||||||
return 0; /* FAC > operand */
|
return 0; /* FAC > operand */
|
||||||
else if (facexp < fopexp) { /* compare exponents */
|
else if (facexp < fopexp) { /* compare exponents */
|
||||||
SETLT; /* FAC < operand */
|
SETLT; /* FAC < operand */
|
||||||
return 2;
|
return 2;
|
||||||
|
|||||||
2
makefile
2
makefile
@@ -7,7 +7,7 @@ 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 swap.h
|
devpnc.h devamlc.h devsmlc.h swap.h
|
||||||
|
|
||||||
CFLAGS =
|
CFLAGS =
|
||||||
# Uncomment for building on SmartOS/Solaris:
|
# Uncomment for building on SmartOS/Solaris:
|
||||||
|
|||||||
96
regs.h
96
regs.h
@@ -167,51 +167,51 @@ static struct {
|
|||||||
/* this is the number of user register sets for this cpuid */
|
/* this is the number of user register sets for this cpuid */
|
||||||
|
|
||||||
static short regsets[] = { \
|
static short regsets[] = { \
|
||||||
2, /* 00 P400 */
|
2, /* 00 P400 */
|
||||||
2, /* 01 P400 (> REV A U-CODE) */
|
2, /* 01 P400 (> REV A U-CODE) */
|
||||||
2, /* 02 RESERVED */
|
2, /* 02 RESERVED */
|
||||||
2, /* 03 P350 */
|
2, /* 03 P350 */
|
||||||
2, /* 04 P450/P550 */
|
2, /* 04 P450/P550 */
|
||||||
2, /* 05 P750 */
|
2, /* 05 P750 */
|
||||||
2, /* 06 P650 */
|
2, /* 06 P650 */
|
||||||
2, /* 07 P150/P250 */
|
2, /* 07 P150/P250 */
|
||||||
2, /* 08 P850 */
|
2, /* 08 P850 */
|
||||||
2, /* 09 MOLE/550 */
|
2, /* 09 MOLE/550 */
|
||||||
2, /* 10 MOLE/650 */
|
2, /* 10 MOLE/650 */
|
||||||
2, /* 11 P2250 */
|
2, /* 11 P2250 */
|
||||||
2, /* 12 P750Y */
|
2, /* 12 P750Y */
|
||||||
2, /* 13 P550Y */
|
2, /* 13 P550Y */
|
||||||
2, /* 14 P850Y */
|
2, /* 14 P850Y */
|
||||||
4, /* 15 P9950 */
|
4, /* 15 P9950 */
|
||||||
8, /* 16 P9650 */
|
8, /* 16 P9650 */
|
||||||
8, /* 17 P2550 */
|
8, /* 17 P2550 */
|
||||||
4, /* 18 P9955 */
|
4, /* 18 P9955 */
|
||||||
4, /* 19 P9750 */
|
4, /* 19 P9750 */
|
||||||
2, /* 20 TBD */
|
2, /* 20 TBD */
|
||||||
8, /* 21 P2350 */
|
8, /* 21 P2350 */
|
||||||
8, /* 22 P2655 */
|
8, /* 22 P2655 */
|
||||||
8, /* 23 P9655 */
|
8, /* 23 P9655 */
|
||||||
4, /* 24 P9955-TIGGER */
|
4, /* 24 P9955-TIGGER */
|
||||||
8, /* 25 P2450 */
|
8, /* 25 P2450 */
|
||||||
4, /* 26 P4050 */
|
4, /* 26 P4050 */
|
||||||
4, /* 27 P4150 */
|
4, /* 27 P4150 */
|
||||||
4, /* 28 P6350 */
|
4, /* 28 P6350 */
|
||||||
4, /* 29 P6550 */
|
4, /* 29 P6550 */
|
||||||
4, /* 30 P9955-II */
|
4, /* 30 P9955-II */
|
||||||
8, /* 31 P2755 */
|
8, /* 31 P2755 */
|
||||||
8, /* 32 P2455 */
|
8, /* 32 P2455 */
|
||||||
4, /* 33 P5310 */
|
4, /* 33 P5310 */
|
||||||
4, /* 34 P9755 */
|
4, /* 34 P9755 */
|
||||||
4, /* 35 P2850 */
|
4, /* 35 P2850 */
|
||||||
4, /* 36 P2950 */
|
4, /* 36 P2950 */
|
||||||
4, /* 37 P5330 */
|
4, /* 37 P5330 */
|
||||||
4, /* 38 P4450 */
|
4, /* 38 P4450 */
|
||||||
4, /* 39 P5370 */
|
4, /* 39 P5370 */
|
||||||
4, /* 40 P6650 */
|
4, /* 40 P6650 */
|
||||||
4, /* 41 P6450 */
|
4, /* 41 P6450 */
|
||||||
4, /* 42 P6150 */
|
4, /* 42 P6150 */
|
||||||
4, /* 43 P5320 */
|
4, /* 43 P5320 */
|
||||||
4}; /* 44 P5340 */
|
4}; /* 44 P5340 */
|
||||||
|
|
||||||
static union {
|
static union {
|
||||||
int rs[REGSETS][32];
|
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 */
|
/* get 64-bit signed at 16-bit offset */
|
||||||
//#define getcrs64s(offset) *(long long *)(crs+(offset))
|
//#define getcrs64s(offset) *(long long *)(crs+(offset))
|
||||||
static inline int64_t getcrs64s(int 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 */
|
/* 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) */
|
/* put 64-bit double at 16-bit offset (remove later) */
|
||||||
//#define putcrs64d(offset, val) *(double *)(crs+(offset)) = (val)
|
//#define putcrs64d(offset, val) *(double *)(crs+(offset)) = (val)
|
||||||
static inline void putcrs64d(int offset, double 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 */
|
/* 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 */
|
For FP 0, offset=0; for FP 1, offset=2 */
|
||||||
//#define putfr64d(offset, val) *(double *)(crsl+FAC0+offset) = (val)
|
//#define putfr64d(offset, val) *(double *)(crsl+FAC0+offset) = (val)
|
||||||
static inline void putfr64d(int offset, double 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
|
#define PCBLEV 0
|
||||||
|
|||||||
35
util/cmraw.c
Normal file
35
util/cmraw.c
Normal 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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user