4.3BSD/usr/src/games/compat/dofloat.c

Compare this file to the similar file:
Show the results in this format:

#ifndef	lint
static char sccsid[] = "	dofloat.c	4.2	84/05/05	";
#endif

/* From Lou Salkind: compat/RCS/dofloat.c,v 1.2 84/01/31 13:33:53 */

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

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