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

5 Commits

Author SHA1 Message Date
Dennis Boone
74aa7fe23e Trial command line option to suppress updating PRIMOS' DATNOW variable. 2025-09-29 20:38:30 -04:00
Dennis Boone
1819fed512 Error in link to install instructions
The link in README.md to install instructions was either old or
never quite right.  Point to DRB's overview document now, which
points (near) to the version specific ones.
2022-03-21 15:24:01 -04:00
Dennis Boone
64c5970e97 Added tracing for floating point operations. 2021-12-13 14:02:01 -05:00
Dennis Boone
c6c0344004 Additional #ifdef __APPLE__ sections removed
Some DTR handling was still inside of such #ifdefs, and thus
I was unable to make a modem work on a serial port.  I believe
this code is portable to OSX, Linux, FreeBSD, and Solaris.
2021-09-05 16:40:13 -04:00
Dennis Boone
0466b4b603 Emit mark parity space(s) in the "less than three" case, not space
parity ones.  Discovered by Daiyu.
2021-07-27 14:59:27 -04:00
6 changed files with 125 additions and 58 deletions

View File

@@ -55,7 +55,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_installing_primos.html). [here](https://sysovl.info/reference_prime_drb_installoview.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).

View File

@@ -1,4 +1,4 @@
/* /*
Implements the AMLC subsystem for Primos. In earlier versions Implements the AMLC subsystem for Primos. In earlier versions
(r186), a more hardware-centric implementation was used that closely (r186), a more hardware-centric implementation was used that closely
followed the design of Prime's real AMLC board. For example, every followed the design of Prime's real AMLC board. For example, every
@@ -52,9 +52,9 @@
NOTE: varying the AMLC poll rates dynamically is the default, but NOTE: varying the AMLC poll rates dynamically is the default, but
this can lead to unpredictable performance. If consistent, this can lead to unpredictable performance. If consistent,
predictable performance is more important than absolute predictable performance is more important than absolute
performance, MAXAMLCSPEEDUP can be set to 1. Then this performance, MAXAMLCSPEEDUP can be set to 1. Then this
implementation will function more or less like a real Prime. implementation will function more or less like a real Prime.
AMLC I/O operations: AMLC I/O operations:
@@ -133,7 +133,7 @@
AMLC status word (from AMLCT5): AMLC status word (from AMLCT5):
BITS DESCRIPTION BITS DESCRIPTION
1 END OF RANGE INTERRUPT 1 END OF RANGE INTERRUPT
2 CLOCK RUNNING 2 CLOCK RUNNING
3-6 LINE # OF LINE WHOSE DATA SET STATUS HAS CHANGED 3-6 LINE # OF LINE WHOSE DATA SET STATUS HAS CHANGED
@@ -150,6 +150,8 @@ 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 */
@@ -202,11 +204,11 @@ int devamlc (int class, int func, int device) {
#define DSSCOUNTDOWN 25 #define DSSCOUNTDOWN 25
/* connection types for each line. This _doesn't_ imply the line is /* connection types for each line. This _doesn't_ imply the line is
actually connected, ie, an AMLC line may be tied to a specific actually connected, ie, an AMLC line may be tied to a specific
serial device (like a USB->serial gizmo), but the USB device may serial device (like a USB->serial gizmo), but the USB device may
not be plugged in. The connection type would be CT_SERIAL but not be plugged in. The connection type would be CT_SERIAL but
the line's fd would be -1 and the "connected" bit would be 0 */ the line's fd would be -1 and the "connected" bit would be 0 */
#define CT_SOCKET 1 #define CT_SOCKET 1
#define CT_SERIAL 2 #define CT_SERIAL 2
#define CT_DEDIP 3 #define CT_DEDIP 3
@@ -324,7 +326,7 @@ int devamlc (int class, int func, int device) {
int tempport; int tempport;
struct hostent* host; struct hostent* host;
char *p; char *p;
/* initially, we don't know about any AMLC boards */ /* initially, we don't know about any AMLC boards */
for (dx=0; dx<MAXBOARDS; dx++) { for (dx=0; dx<MAXBOARDS; dx++) {
@@ -346,7 +348,7 @@ int devamlc (int class, int func, int device) {
/* read the amlc.cfg file. This file has 3 uses: /* read the amlc.cfg file. This file has 3 uses:
1. maps Prime async lines to real serial devices, like host 1. maps Prime async lines to real serial devices, like host
serial ports or USB serial boxes. serial ports or USB serial boxes.
Format: <line #> /dev/<Unix usb device name> Format: <line #> /dev/<Unix usb device name>
@@ -418,7 +420,7 @@ int devamlc (int class, int func, int device) {
fprintf(stderr,"Line %d of amlc.cfg ignored: IP address too long\n", lc); fprintf(stderr,"Line %d of amlc.cfg ignored: IP address too long\n", lc);
continue; continue;
} }
/* break out host and port number; no port means this is /* break out host and port number; no port means this is
an incoming dedicated line: no connects out. With a an incoming dedicated line: no connects out. With a
port means we need to connect to it. */ port means we need to connect to it. */
@@ -553,13 +555,13 @@ int devamlc (int class, int func, int device) {
/* XXX: this constant is redefined because of a bug in the /* XXX: this constant is redefined because of a bug in the
OSX Prolific USB serial driver at version 1.2.1r2. They should be OSX Prolific USB serial driver at version 1.2.1r2. They should be
turning on bit 0100, but are turning on 0x0100. */ turning on bit 0100, but are turning on 0x0100. */
#define TIOCM_CD 0x0100 #define TIOCM_CD 0x0100
if (func == 00) { /* input Data Set Sense (carrier) */ if (func == 00) { /* input Data Set Sense (carrier) */
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;
@@ -575,7 +577,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);
@@ -634,10 +636,10 @@ int devamlc (int class, int func, int device) {
} }
break; break;
case CT_SERIAL: { case CT_SERIAL: {
int fd; int fd;
/* setup line characteristics if they have changed (check for /* setup line characteristics if they have changed (check for
something other than DTR changing) */ something other than DTR changing) */
@@ -707,7 +709,7 @@ int devamlc (int class, int func, int device) {
1_0 - cts/rts flow control (2413 becomes 6413) 1_0 - cts/rts flow control (2413 becomes 6413)
1_1 - dsr/dtr flow control (2413 becomes 7413) 1_1 - dsr/dtr flow control (2413 becomes 7413)
NOTE: bit 11 also appears to be free, but Primos doesn't NOTE: bit 11 also appears to be free, but Primos doesn't
let it flow through to the AMLC controller. :( let it flow through to the AMLC controller. :(
*/ */
@@ -758,7 +760,6 @@ 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");
@@ -771,7 +772,6 @@ int devamlc (int class, int func, int device) {
} }
ioctl(fd, TIOCMSET, &modemstate); ioctl(fd, TIOCMSET, &modemstate);
} }
#endif
break; break;
} }
@@ -841,7 +841,7 @@ int devamlc (int class, int func, int device) {
double ts; double ts;
int neweor, activelines; int neweor, activelines;
//printf("poll device '%o, speedup=%5.2f, cti=%x, xmit=%x, recv=%x, dss=%x\n", device, pollspeedup, dc[dx].ctinterrupt, dc[dx].xmitenabled, dc[dx].recvenabled, dc[dx].dss); //printf("poll device '%o, speedup=%5.2f, cti=%x, xmit=%x, recv=%x, dss=%x\n", device, pollspeedup, dc[dx].ctinterrupt, dc[dx].xmitenabled, dc[dx].recvenabled, dc[dx].dss);
/* check for 1 new telnet connection every AMLCACCEPTSECS seconds /* check for 1 new telnet connection every AMLCACCEPTSECS seconds
(10 times per second) */ (10 times per second) */
@@ -1036,7 +1036,7 @@ int devamlc (int class, int func, int device) {
int fd, sockflags; int fd, sockflags;
struct sockaddr_in raddr; struct sockaddr_in raddr;
dc[dx].obtimer[lx] = tv.tv_sec + AMLCCONNECT; dc[dx].obtimer[lx] = tv.tv_sec + AMLCCONNECT;
//printf("em: trying to connect to 0x%08x:%d\n", dc[dx].obhost[lx], dc[dx].obport[lx]); /***/ //printf("em: trying to connect to 0x%08x:%d\n", dc[dx].obhost[lx], dc[dx].obport[lx]); /***/
fd = socket(AF_INET, SOCK_STREAM, 0); fd = socket(AF_INET, SOCK_STREAM, 0);
@@ -1121,7 +1121,7 @@ int devamlc (int class, int func, int device) {
} }
/* process input, but only as much as will fit into the DMC /* process input, but only as much as will fit into the DMC
buffer. buffer.
Because the size of the AMLC tumble tables is limited, this Because the size of the AMLC tumble tables is limited, this
could pose a denial of service issue. Input is processed in a could pose a denial of service issue. Input is processed in a

9
em.c
View File

@@ -274,6 +274,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
T_EAV trace V-mode effective address calculation T_EAV trace V-mode effective address calculation
T_EAI trace I-mode effective address calculation T_EAI trace I-mode effective address calculation
T_FLOW instruction summary T_FLOW instruction summary
T_FP floating point
T_INST detailed instruction trace T_INST detailed instruction trace
T_MODE trace CPU mode changes T_MODE trace CPU mode changes
T_EAAP AP effective address calculation T_EAAP AP effective address calculation
@@ -311,6 +312,7 @@ static void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int
#define T_EAS 0x00040000 #define T_EAS 0x00040000
#define T_TLB 0x00080000 #define T_TLB 0x00080000
#define T_SMLC 0x00100000 #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))
@@ -657,6 +659,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 dolinecleararg; /* -dolineclear arg */
@@ -4454,6 +4457,7 @@ int main (int argc, char **argv) {
#include "dispatch.h" #include "dispatch.h"
noclock = 0;
domemdump = 0; domemdump = 0;
dolinecleararg = 0; dolinecleararg = 0;
bootarg = NULL; bootarg = NULL;
@@ -4472,6 +4476,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;
@@ -4618,6 +4625,8 @@ int main (int argc, char **argv) {
gv.traceflags |= T_TLB; gv.traceflags |= T_TLB;
else if (strcmp(argv[i],"smlc") == 0) else if (strcmp(argv[i],"smlc") == 0)
gv.traceflags |= T_SMLC; gv.traceflags |= T_SMLC;
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 (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1) else if (strlen(argv[i]) == 6 && sscanf(argv[i],"%o", &templ) == 1)

44
emdev.h
View File

@@ -51,7 +51,7 @@
'50 = #1 HSSMLC/MDLC (synchronous comm) '50 = #1 HSSMLC/MDLC (synchronous comm)
'51 = #2 HSSMLC/MDLC '51 = #2 HSSMLC/MDLC
* '52 = #3 AMLC or ICS1 * '52 = #3 AMLC or ICS1
* '53 = #2 AMLC * '53 = #2 AMLC
* '54 = #1 AMLC * '54 = #1 AMLC
'55 = MACI autocall unit '55 = MACI autocall unit
'56 = old SMLC (RTOS User Guide, A-1 & Hacker's Guide) '56 = old SMLC (RTOS User Guide, A-1 & Hacker's Guide)
@@ -229,7 +229,7 @@ int devnone (int class, int func, int device) {
OCP '0604 = enable transmit DMA/C OCP '0604 = enable transmit DMA/C
OCP '0704 = reset transmit interrupt mask and DMA/C enable OCP '0704 = reset transmit interrupt mask and DMA/C enable
OCP '1004 = Full duplex; software must echo OCP '1004 = Full duplex; software must echo
OCP '1104 = output a sync pulse (diagnostics) OCP '1104 = output a sync pulse (diagnostics)
OCP '1204 = Prime normal, independent xmit and recv w/echoplex OCP '1204 = Prime normal, independent xmit and recv w/echoplex
OCP '1304 = Self test mode (internally connects transmitter to receiver) OCP '1304 = Self test mode (internally connects transmitter to receiver)
OCP '1504 = Set both xmit & rcv interrupt masks OCP '1504 = Set both xmit & rcv interrupt masks
@@ -302,7 +302,7 @@ int devasr (int class, int func, int device) {
int doblock; int doblock;
time_t unixtime; time_t unixtime;
struct tm *tms; struct tm *tms;
doblock = BLOCKIO; doblock = BLOCKIO;
switch (class) { switch (class) {
@@ -330,7 +330,7 @@ int devasr (int class, int func, int device) {
perror(" unable to get tty attributes"); perror(" unable to get tty attributes");
fatal(NULL); fatal(NULL);
} }
/* save initial terminal setup to restore when exiting */ /* save initial terminal setup to restore when exiting */
origterminfo = terminfo; origterminfo = terminfo;
@@ -497,7 +497,7 @@ readasr:
goto readasr; goto readasr;
} }
#endif #endif
/* if doing local echo, do xon/xoff processing here. If Unix /* if doing local echo, do xon/xoff processing here. If Unix
does it, the emulator might block on a console write. If does it, the emulator might block on a console write. If
the console is running full-duplex (no local echo), we can the console is running full-duplex (no local echo), we can
@@ -650,7 +650,7 @@ readasr:
/* Device '14 - magtape controller #1 /* Device '14 - magtape controller #1
NOTES: NOTES:
This code only supports 1 tape controller (4 units), but could be This code only supports 1 tape controller (4 units), but could be
extended to support 2 controllers (eg, see disk controller code) extended to support 2 controllers (eg, see disk controller code)
@@ -863,7 +863,7 @@ fmterr:
*mtstat |= 0x100; /* set filemark status */ *mtstat |= 0x100; /* set filemark status */
goto repo; goto repo;
} }
/* ignore attempts to backspace over error records. This will /* ignore attempts to backspace over error records. This will
cause Magsav to read the next record instead, and it may cause Magsav to read the next record instead, and it may
recover. Re-reading the error record 10 times won't help! */ recover. Re-reading the error record 10 times won't help! */
@@ -881,7 +881,7 @@ fmterr:
} }
/* read leading reclen again to make sure we're positioned correctly */ /* read leading reclen again to make sure we're positioned correctly */
n = read(fd, buf, 4); n = read(fd, buf, 4);
if (n == -1) goto readerr; if (n == -1) goto readerr;
if (n != 4) { if (n != 4) {
@@ -974,7 +974,7 @@ int devmt (int class, int func, int device) {
enabled = 1; enabled = 1;
if (interrupting == 1) /* if interrupt is pending */ if (interrupting == 1) /* if interrupt is pending */
devpoll[device] = 10; /* try to interrupt soon */ devpoll[device] = 10; /* try to interrupt soon */
} else if (func == 016) { /* reset interrupt mask */ } else if (func == 016) { /* reset interrupt mask */
enabled = 0; enabled = 0;
@@ -1092,7 +1092,7 @@ int devmt (int class, int func, int device) {
} else } else
unit[u].mtstat = 0x00C8; /* Ready, Online, BOT */ unit[u].mtstat = 0x00C8; /* Ready, Online, BOT */
} }
/* "select only" is ignored. On a real tape controller, this /* "select only" is ignored. On a real tape controller, this
blocks (I think) if the previous tape operation is in progress */ blocks (I think) if the previous tape operation is in progress */
@@ -1276,12 +1276,12 @@ int devmt (int class, int func, int device) {
} }
IOSKIP; IOSKIP;
break; break;
} else if (func == 02) { } else if (func == 02) {
ready = 1; ready = 1;
if (getcrs16(A) & 0x8000) { /* status word 1 */ if (getcrs16(A) & 0x8000) { /* status word 1 */
datareg = unit[usel].mtstat; datareg = unit[usel].mtstat;
/* if the tape was rewinding, return rewinding status once, then /* if the tape was rewinding, return rewinding status once, then
change it to BOT */ change it to BOT */
@@ -1413,7 +1413,9 @@ 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);
put32r0(datnow, datnowea); if (! noclock) {
put32r0(datnow, datnowea);
}
} }
@@ -1438,7 +1440,7 @@ int devcp (int class, int func, int device) {
case -1: case -1:
/* if -map is used, lookup DATNOW symbol and set the 32-bit /* if -map is used, lookup DATNOW symbol and set the 32-bit
Primos time value (DATNOW+TIMNOW) */ Primos time value (DATNOW+TIMNOW) */
datnowea = 0; datnowea = 0;
@@ -1455,10 +1457,10 @@ int devcp (int class, int func, int device) {
; ;
} else if (func == 01) { /* ack PIC interrupt */ } else if (func == 01) { /* ack PIC interrupt */
; ;
} else if (func == 02) { /* stop LFC (IO.PNC DIAG) */ } else if (func == 02) { /* stop LFC (IO.PNC DIAG) */
; ;
} else if (func == 04) { /* does something on VCP during boot */ } else if (func == 04) { /* does something on VCP during boot */
; ;
@@ -1581,7 +1583,7 @@ int devcp (int class, int func, int device) {
previnstcount = gv.instcount; previnstcount = gv.instcount;
if (datnowea != 0) if (datnowea != 0)
initclock(datnowea); initclock(datnowea);
} }
elapsedms = (tv.tv_sec-start_tv.tv_sec)*1000.0 + (tv.tv_usec-start_tv.tv_usec)/1000.0; elapsedms = (tv.tv_sec-start_tv.tv_sec)*1000.0 + (tv.tv_usec-start_tv.tv_usec)/1000.0;
targetticks = elapsedms/(-clkpic*clkrate/1000); targetticks = elapsedms/(-clkpic*clkrate/1000);
#if 0 #if 0
@@ -1595,7 +1597,7 @@ int devcp (int class, int func, int device) {
available (no Primos maps), then we have to tick our way to available (no Primos maps), then we have to tick our way to
the correct time. In addition to lowering overhead, slower the correct time. In addition to lowering overhead, slower
clock tick rates make catching up much faster. clock tick rates make catching up much faster.
When ticking faster, we need to be careful not to tick too When ticking faster, we need to be careful not to tick too
fast, because that will cause timed events like disk I/O to fast, because that will cause timed events like disk I/O to
timeout prematurely. With rev 20 Primos, setting the timeout prematurely. With rev 20 Primos, setting the
@@ -1812,7 +1814,7 @@ int devdisk (int class, int func, int device) {
dc[dx].unit[u].modrecs = NULL; dc[dx].unit[u].modrecs = NULL;
} }
return 0; return 0;
case 0: case 0:
TRACE(T_INST|T_DIO, " OCP '%2o%2o\n", func, device); TRACE(T_INST|T_DIO, " OCP '%2o%2o\n", func, device);
if (func == 016) { /* reset interrupt */ if (func == 016) { /* reset interrupt */
@@ -2017,7 +2019,7 @@ int devdisk (int class, int func, int device) {
} }
dmaaddr = ((getar16(REGDMX16+dmareg) & 3)<<16) | getar16(REGDMX16+dmareg+1); dmaaddr = ((getar16(REGDMX16+dmareg) & 3)<<16) | getar16(REGDMX16+dmareg+1);
TRACE(T_INST|T_DIO, " DMA channels: nch-1=%d, ['%o]='%o, ['%o]='%o, nwords=%d\n", dc[dx].dmanch, dc[dx].dmachan, swap16(regs.sym.regdmx[dmareg]), dc[dx].dmachan+1, dmaaddr, dmanw); TRACE(T_INST|T_DIO, " DMA channels: nch-1=%d, ['%o]='%o, ['%o]='%o, nwords=%d\n", dc[dx].dmanch, dc[dx].dmachan, swap16(regs.sym.regdmx[dmareg]), dc[dx].dmachan+1, dmaaddr, dmanw);
if (order == 5) { /* read */ if (order == 5) { /* read */
if (getcrs16(MODALS) & 020) /* mapped read */ if (getcrs16(MODALS) & 020) /* mapped read */
if ((dmaaddr & 01777) || dmanw > 1024) if ((dmaaddr & 01777) || dmanw > 1024)
@@ -2078,7 +2080,7 @@ int devdisk (int class, int func, int device) {
} }
TRACE(T_INST|T_DIO, " seek track %d, restore=%d, clear=%d\n", track, (m1 & 0100000) != 0, (m1 & 040000) != 0); TRACE(T_INST|T_DIO, " seek track %d, restore=%d, clear=%d\n", track, (m1 & 0100000) != 0, (m1 & 040000) != 0);
#if 0 #if 0
/* this has been disabled because SCSI drives sometimes seek to /* this has been disabled because SCSI drives sometimes seek to
track 512 (special meaning in controller?) */ track 512 (special meaning in controller?) */
if (track > dc[dx].unit[u].maxtrack) { if (track > dc[dx].unit[u].maxtrack) {

84
fp.h
View File

@@ -40,6 +40,7 @@ http://tima-cmp.imag.fr/~guyot/Cours/Oparithm/english/Op_Ar2.htm
inline void getdp (unsigned long long p, long long *frac64, int *exp32) { 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 */
} }
@@ -59,22 +60,29 @@ 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;
} }
@@ -82,13 +90,15 @@ 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;
} }
/* 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--;
} }
@@ -98,7 +108,10 @@ 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;
@@ -113,6 +126,7 @@ int prieee8(unsigned long long dp, double *d) {
/* pack into an IEEE DPFP, losing the leading 1 bit in the process */ /* 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;
} }
@@ -134,7 +148,7 @@ retry:
neg = frac64 < 0; neg = frac64 < 0;
exp32 = (frac64 >> 52) & 0x7ff; exp32 = (frac64 >> 52) & 0x7ff;
frac64 &= 0xfffffffffffffLL; frac64 &= 0xfffffffffffffLL;
//printf("dp=%llx, neg=%d, frac64=%llx, exp32=%d, \n", *(long long *)dp, neg, frac64, exp32); TRACE(T_FP, "d=%016llx, neg=%x, frac64=%016llx, exp32=%08x, \n", (long long)d, neg, frac64, exp32);
/* special case: NaN & +-infinity */ /* special case: NaN & +-infinity */
@@ -159,12 +173,21 @@ 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) */
@@ -173,12 +196,14 @@ 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
@@ -204,8 +229,11 @@ 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;
@@ -260,6 +288,7 @@ 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 */
@@ -290,6 +319,7 @@ 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--;
@@ -314,11 +344,16 @@ 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)
@@ -329,8 +364,10 @@ 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;
} }
} }
@@ -356,26 +393,37 @@ 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 */
}
} }
@@ -386,7 +434,7 @@ int fcs (unsigned long long fac, int fop) {
NOTE: This code doesn't pass Prime diagnostics for higher model NOTE: This code doesn't pass Prime diagnostics for higher model
CPU's, I'm guessing because comparison is implemented as subtract, CPU's, I'm guessing because comparison is implemented as subtract,
and we can't do that because numbers with huge exponents (and and we can't do that because numbers with huge exponents (and
Prime ASCII characters in the DAC) won't convert to IEEE. Prime ASCII characters in the DAC) won't convert to IEEE.
*/ */
@@ -404,27 +452,35 @@ int dfcs (unsigned long long fac, long long fop) {
fop = fop & 0xffffffffffff0000LL; fop = fop & 0xffffffffffff0000LL;
if (fop == 0) /* fix dirty zero */ if (fop == 0) /* fix dirty zero */
fopexp = 0; fopexp = 0;
#if 0 TRACE(T_FP, " dfcs: FAC: %016llx %04x; op: %016llx %04x\n", templl, facexp, fop, fopexp);
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

@@ -1,5 +1,5 @@
/* utextp.c, Jim Wilcoxson, March 16, 2005 /* utextp.c, Jim Wilcoxson, March 16, 2005
Reads a Unix text file and converts it to a compressed Prime text file. Reads a Unix text file and converts it to a compressed Prime text file.
This means: This means:
- turn high bit on - turn high bit on
- expand Unix tabs to spaces - expand Unix tabs to spaces
@@ -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(' '); putchar(0240);
space--; space--;
n++; n++;
} else { /* write compressed spaces */ } else { /* write compressed spaces */