PDP-11 Compatability Mode on VAXen

utzoo!decvax!ucbvax!unix-wizards utzoo!decvax!ucbvax!unix-wizards
Thu Sep 17 13:42:36 AEST 1981


>From allegra!jdd at Berkeley Thu Sep 17 12:43:20 1981
In reply to my message of 15 Sep 1981 13:32:48-PDT on bugs in the PDP-11
compatability mode package on the VAX, I received a request for the specific
changes.  Well, since I'm not on the Arpanet, I can't send to individuals,
only to mailing lists, so, everybody, here are some changes.  I apologize
for their length.

To (partially) fix the problem of stack frames being created prematurely
when signals are caught while in compatability mode, one should change files
unixtraps.c and dosig.c .  In unixtraps.c, add the line:

	int interrupt;

in the external declarations at the top.  Add the line:

	interrupt = 0

as the first executable statement of routine dotrap().  Add the line:

	if (interrupt) dosig(interrupt, pc);

as the last executable statement in routine dotrap().

In dosig.c, add the line:

	extern int interrupt;

in the external declarations at the top.  Change the first call to
dosig(signum, pc) in routine sigcatch() to the line:

	interrupt = signum;

These changes help the problem, but they do not solve it.  First, they do
not handle multiple signals caught while in native mode; only one is
remembered.  Secondly, there are numerous timing problems which could mess
things up, but this is much hairier to solve, mostly since signals are so
hard to use (although easier under Berkeley Unix).

As for the floating-point package, it's at the end of this note.  It is not
a complete package in that it does not simulate all of the hardware
features, but it seems to be close enough for C programs and the run-time
library.

Cheers,
John DeTreville

------------------------------dofloat.c-------------------------------

/* Partial PDP-11 floating-point simulator.  Always in double mode,
   chop mode.  All arithmetic done in double-precision. Storing longs
   into or taking longs from general registers doesn't work.
   Overflow is never detected.  Other things are wrong too. */

#include <stdio.h>
#include "defs.h"

#define TRUE 1
#define FALSE 0

#define ABSD	0170600
#define ADDD	0172000
#define CFCC	0170000
#define CLRD	0170400
#define CMPD	0173400
#define DIVD	0174400
#define LDCFD	0177400
#define LDCLD	0177000
#define LDD	0172400
#define LDEXP	0176400
#define MODD	0171400
#define MULD	0171000
#define NEGD	0170700
#define SETD	0170011
#define SETI	0170002
#define SETL	0170012
#define STCDL	0175400
#define STCDF	0176000
#define STD	0174000
#define STEXP	0175000
#define SUBD	0173000
#define TSTD	0170500

static struct {
	unsigned fc :1;
	unsigned fv :1;
	unsigned fz :1;
	unsigned fn :1;
	unsigned fmm :1;
	unsigned ft :1;
	unsigned fl :1;
	unsigned fd :1;
} fps = FALSE;

#define FZ fps.fz
#define FN fps.fn
#define FL fps.fl
#define FD fps.fd

#define LMODE FL
#define IMODE (!LMODE)

static double fregs[6];

dofloat(instr)
unsigned int instr;
{
	int mode, reg, ac;
	unsigned short * x, * resolve();
#define DOUBLE (*((double *)x))
#define FLOAT (*(float *)x)
#define LONG (*(long *)x)
#define SHORT (*(short *)x)
#define GETDOUBLE (x = resolve(mode, reg, 8, TRUE))
#define GETFLOAT (x = resolve(mode, reg, 4, TRUE))
#define GETLONG (x = resolve(mode, reg, 4, FALSE))
#define GETSHORT (x = resolve(mode, reg, 2, FALSE))
#define FREG fregs[ac]
	double temp;
	union {
		double d;
		short s;
	} bits;

	switch (instr & 0170000) {
	case 0170000:
		break;
	default:
		fprintf(stderr, "Unrecognized instr in dofloat %0o\n", instr);
		return (-1);
	}

	switch (instr & 07000) {
	case 0:
		switch (instr & 0700) {
		case 0:
			switch (instr) {
			case CFCC:
				psl &= ~017;
				if (FN) {
					psl |= 010;
				}
				if (FZ) {
					psl |= 04;
				}
				return (0);
			case SETD:
				FD = TRUE;
				return (0);
			case SETI:
				FL = FALSE;
				return (0);
			case SETL:
				FL = TRUE;
				return (0);
			default:
				fprintf(stderr, "Unrecognized instr in dofloat %0o\n", instr);
				return (-1);
			}
		default:
			break;
		}

		mode = (instr & 070) >> 3;
		reg = instr & 07;

		switch (instr & 0177700) {
		case ABSD:
			GETDOUBLE;
			if (DOUBLE < 0.0) {
				DOUBLE = -DOUBLE;
			}
			FZ = (DOUBLE == 0.0);
			FN = (DOUBLE < 0.0);
			return (0);
		case CLRD:
			GETDOUBLE;
			DOUBLE = 0.0;
			FZ = TRUE;
			FN = FALSE;
			return (0);
		case NEGD:
			GETDOUBLE;
			DOUBLE = -DOUBLE;
			FZ = (DOUBLE == 0.0);
			FN = (DOUBLE < 0.0);
			return (0);
		case TSTD:
			GETDOUBLE;
			FZ = (DOUBLE == 0.0);
			FN = (DOUBLE < 0.0);
			return (0);
		default:
			fprintf(stderr, "Unrecognized instr in dofloat %0o\n", instr);
			return (-1);
		}
	default:
		break;
	}

	ac = (instr & 0300) >> 6;
	mode = (instr & 070) >> 3;
	reg = instr & 07;

	switch (instr & 0177400) {
	case ADDD:
		GETDOUBLE;
		FREG += DOUBLE;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case CMPD:
		GETDOUBLE;
		FZ = (DOUBLE == FREG);
		FN = (DOUBLE < FREG);
		return (0);
	case DIVD:
		GETDOUBLE;
		FREG /= DOUBLE;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case LDCFD:
		GETFLOAT;
		FREG = FLOAT;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case LDCLD:
		if (IMODE) {
			GETSHORT;
			FREG = SHORT;
		} else {
			GETLONG;
			FREG = fliplong(LONG);
		}
		FZ = (FREG == 0 .0);
		FN = (FREG < 0.0);
		return (0);
	case LDD:
		GETDOUBLE;
		FREG = DOUBLE;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case LDEXP:
		GETSHORT;
		bits.d = FREG;
		bits.s &= ~077600;
		bits.s |= (SHORT + 0200) << 7;
		FREG = bits.d;
		FZ = (SHORT == 0);
		FN = (FREG < 0.0);
		return (0);
	case MODD:
		GETDOUBLE;
		temp = FREG * DOUBLE;
		fregs[ac|1] = (long) temp;
		FREG = temp - (long) temp;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case MULD:
		GETDOUBLE;
		FREG = FREG * DOUBLE;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case STCDF:
		GETFLOAT;
		FLOAT = FREG;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case STCDL:
		if (IMODE) {
			GETSHORT;
			SHORT = FREG;
			psl &= ~017;
			if (SHORT == 0) {
				psl |= 04;
			}
			if (SHORT < 0) {
				psl |= 010;
			}
		} else {
			GETLONG;
			LONG = fliplong((long) FREG);
			psl &= ~017;
			if (fliplong(LONG) == 0) {
				psl |= 04;
			}
			if (fliplong(LONG) < 0) {
				psl |= 010;
			}
		}
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	case STD:
		GETDOUBLE;
		DOUBLE = FREG;
		return (0);
	case STEXP:
		GETSHORT;
		bits.d = FREG;
		SHORT = ((bits.s & 077600) >> 7) - 0200;
		FZ = (SHORT == 0);
		FN = (SHORT < 0);
		psl &= ~017;
		if (FZ) {
			psl |= 04;
		}
		if (FN) {
			psl |= 010;
		}
		return (0);
	case SUBD:
		GETDOUBLE;
		FREG -= DOUBLE;
		FZ = (FREG == 0.0);
		FN = (FREG < 0.0);
		return (0);
	default:
		fprintf(stderr, "Unrecognized instr in dofloat %0o\n", instr);
		return (-1);
	}
}

unsigned short *
resolve(mode, reg, bytes, floating)
{
	static unsigned short *x;
	static union {
		double d;
		unsigned short s;
	} bits;

	switch (mode) {
	case 0:
		if (floating) {
			if (bytes != 8) {
				fprintf(stderr, "Bad length in dofloat\n");
				return ((unsigned short *) -1);
			}
			x = (unsigned short *) &fregs[reg];
		} else {
			if (bytes != 2) {
				fprintf(stderr, "Bad length in dofloat\n");
				return ((unsigned short *) -1);
			}
			x = (unsigned short *) &regs[reg];
		}
		break;
	case 1:
		x = (unsigned short *) regs[reg];
		break;
	case 2:
		if (reg == 7 && floating) {
			bits.d = 0.0;
			bits.s = *(unsigned short *) regs[7];
			x = (unsigned short *) &bits;
			regs[7] += 2;
			pc = (unsigned short *) regs[7];
		} else {
			x = (unsigned short *) regs[reg];
			regs[reg] += bytes;
			if (reg == 7) {
				if (bytes != 2) {
					return((unsigned short *) -1);
				}
				pc = (unsigned short *) regs[7];
			}
		}
		break;
	case 3:
		x = (unsigned short *) regs[reg];
		x = (unsigned short *) *x;
		regs[reg] += 2;
		if (reg == 7) {
			pc = (unsigned short *) regs[7];
		}
		break;
	case 4:
		regs[reg] -= bytes;
		if (reg == 7) {
			pc = (unsigned short *) regs[7];
		}
		x = (unsigned short *) regs[reg];
		break;
	case 5:
		regs[reg] -= 2;
		if (reg == 7) {
			pc = (unsigned short *) regs[7];
		}
		x = (unsigned short *) regs[reg];
		x = (unsigned short *) *x;
		break;
	case 6:
		x = (unsigned short *) (unsigned short) (regs[reg] + *(pc++));
		if (reg == 7) {
			++x;
		}
		break;
	case 7:
		x = (unsigned short *) (unsigned short) (regs[reg] + *(pc++));
		if (reg == 7) {
			++x;
		}
		x = (unsigned short *) *x;
		break;
	}

	return (x);
}

long
fliplong(l)
long l;
{
	union {
		long l;
		short s[2];
	} bits[2];

	bits[0].l = l;
	bits[1].s[1] = bits[0].s[0];
	bits[1].s[0] = bits[0].s[1];
	return (bits[1].l);
}

/*-----------------------------the end------------------------------*/



More information about the Comp.unix.wizards mailing list