date and time created 83/03/09 16:22:55 by ralph
[unix-history] / usr / src / old / games.vax / compat / dofloat.c
#
static char sccsid[] = " dofloat.c 4.1 82/05/12 ";
/*
* Simulate pdp11 floating point for compatability mode programs.
* Quick and dirty with no big effort at speed since it takes so
* much overhead to get here in the first place.
* I make no claims on the completeness of this simulation.
* Art Wetzel 3/16/80
*/
#ifndef NOFPSIM
#ifdef DEBUG
#include <stdio.h>
#endif
#include "defs.h"
/* output codes */
#define NONE 0
#define SHORT 01
#define LONG 02
#define FLOAT 04
#define DOUBLE 010
#define OUTPUT 020
/* parts of fps */
#define FD 0200
#define FL 0100
#define FN 010
#define FZ 04
#define FV 02
#define FC 01
/* fis instructions */
#define FADD 075000
#define FSUB 075010
#define FMUL 075020
#define FDIV 075030
/* fpu instructions */
#define ABSD 0170600
#define ABSF 0170600
#define ADDD 0172000
#define ADDF 0172000
#define CFCC 0170000
#define CLRD 0170400
#define CLRF 0170400
#define CMPD 0173400
#define CMPF 0173400
#define DIVD 0174400
#define DIVF 0174400
#define LDCFD 0177400
#define LDCFF 0177400
#define LDCLD 0177000
#define LDCLF 0177000
#define LDCIF 0177000
#define LDCID 0177000
#define LDEXP 0176400
#define LDD 0172400
#define LDF 0172400
#define LDFPS 0170100
#define MODD 0171400
#define MODF 0171400
#define MULD 0171000
#define MULF 0171000
#define NEGD 0170700
#define NEGF 0170700
#define SETF 0170001
#define SETD 0170011
#define SETI 0170002
#define SETL 0170012
#define STCDF 0176000
#define STCFD 0176000
#define STCDL 0175400
#define STCDI 0175400
#define STCFL 0175400
#define STCFI 0175400
#define STEXP 0175000
#define STD 0174000
#define STF 0174000
#define STFPS 0170200
#define STST 0170300
#define SUBD 0173000
#define SUBF 0173000
#define TSTD 0170500
#define TSTF 0170500
union alltypes {
double d;
float f;
long l;
short s;
unsigned short p[4];
};
/* static storage for floating registers */
static union alltypes fregs[6];
static union alltypes srcdst;
int fps = FD|FL;
int dbl = 0;
int lng = 0;
#endif
dofloat(instr) unsigned int instr; {
#ifdef NOFPSIM
return(-1);
#else
register unsigned short *wptr;
register unsigned int opcode, ac, mode, fac, adjust, output, ccset;
unsigned short *locate();
/* indicate what condition codes will be changed by op - assume none */
ccset = 0;
/* type of memory output - assume none */
output = NONE;
/* default adjust to type */
if(dbl)
adjust = DOUBLE;
else
adjust = FLOAT;
/* chop up instruction to get relevent parts */
opcode = instr & 0177700;
fac = (instr>>6) & 03;
mode = (instr>>3) & 07;
ac = instr & 07;
/* if the instruction uses a src/dst construct ptr and fetch */
switch(opcode) {
case FADD:
case CFCC:
break;
default:
wptr = locate(mode, ac);
/* special case for mode 0 */
if(mode == 0) switch(opcode & 0177400) {
/* special instructions to use cpu regs */
case LDEXP:
case STEXP:
wptr = &regs[ac];
break;
case STCDL:
wptr = &regs[ac];
default:
break;
}
if(dbl)
srcdst.d = *(double *)wptr;
else
srcdst.f = *(float *)wptr;
/* immediate fetches are 16 bits */
if(ac == 7 && (mode == 2)) {
srcdst.p[1] = 0;
srcdst.p[2] = 0;
srcdst.p[3] = 0;
}
break;
}
#ifdef DEBUG
fprintf(stderr,"pc %o sp %o instr %o srcdst %o mode %o reg %o fac %o\n", pc-1,regs[6],instr,srcdst.s,mode,ac,fac);
#endif
switch(opcode) {
case FADD:
/* catches all fis instructions */
/* last 3 bits are stack pointer register */
ac = instr & 07;
/* get pointer to stack words */
wptr = (unsigned short *)regs[ac];
/* getch floating value from stack */
srcdst.f = *(float *)wptr;
/* shorten stack */
wptr += 2;
/* do appropriate operation */
switch(instr & 0177770) {
case FADD:
srcdst.f += *(float *)wptr;
break;
case FSUB:
srcdst.f = *(float *)wptr - srcdst.f;
break;
case FMUL:
srcdst.f *= *(float *)wptr;
break;
case FDIV:
srcdst.f = *(float *)wptr / srcdst.f;
break;
default:
return(-1);
}
/* copy out result */
*(float *)wptr = srcdst.f;
/* set up condition codes */
psl &= ~017;
if(srcdst.f == 0.) psl |= FZ;
if(srcdst.f < 0.) psl |= FN;
/* adjust register to reflect stack change */
regs[ac] = (unsigned short)(int)wptr;
return(0);
case CFCC:
switch(instr) {
case SETF:
dbl = 0;
break;
case SETD:
dbl = 1;
break;
case SETI:
lng = 0;
break;
case SETL:
lng = 1;
break;
case CFCC:
psl &= ~017;
psl |= (fps & 017);
#ifdef DEBUG
fprintf(stderr,"CFCC %o\n",psl);
#endif
break;
default:
return(-1);
}
return(0);
case ABSD:
if(srcdst.d < 0.0 ) srcdst.d = -srcdst.d;
ccset = FZ;
if(dbl)
output = DOUBLE;
else
output = FLOAT;
break;
case CLRD:
srcdst.d =0.0;
ccset = FZ;
if(dbl)
output = DOUBLE;
else
output = FLOAT;
break;
case LDFPS:
adjust = SHORT;
fps = srcdst.s;
if(fps & FD)
dbl = 1;
else
dbl = 0;
if(fps & FL )
lng = 1;
else
lng = 0;
break;
case NEGD:
srcdst.d = -srcdst.d;
ccset = FZ|FN;
if(dbl)
output = DOUBLE;
else
output = FLOAT;
break;
case STFPS:
srcdst.s = fps;
adjust = output = SHORT;
break;
case STST:
return(0);
break;
case TSTD:
ccset = FZ|FN;
break;
default:
opcode = instr & 0177400;
switch(opcode) {
case STD:
srcdst.d = fregs[fac].d;
#ifdef DEBUG
fprintf(stderr,"STD %o\n",srcdst.s);
#endif
if(dbl)
output = DOUBLE;
else
output = FLOAT;
break;
case LDD:
#ifdef DEBUG
fprintf(stderr,"LDD %o\n",srcdst.s);
#endif
fregs[fac].d = srcdst.d;
ccset = FZ|FN;
break;
case ADDD:
fregs[fac].d += srcdst.d;
ccset = FZ|FN;
break;
case SUBD:
fregs[fac].d -= srcdst.d;
ccset = FZ|FN;
break;
case MULD:
fregs[fac].d *= srcdst.d;
ccset = FZ|FN;
break;
case DIVD:
#ifdef DEBUG
fprintf(stderr,"DIVD %f by %f gives ",fregs[fac].d,srcdst.d);
#endif
fregs[fac].d /= srcdst.d;
#ifdef DEBUG
fprintf(stderr,"-> %f\n",fregs[fac].d);
#endif
ccset = FZ|FN;
break;
case STCDF:
adjust = output = FLOAT;
ccset = FZ|FN;
break;
case LDCFD:
adjust = FLOAT;
ccset = FZ|FN;
break;
case LDCLD:
if(lng) {
adjust = LONG;
srcdst.d = srcdst.l;
} else {
adjust = SHORT;
srcdst.d = srcdst.s;
}
ccset = FZ|FN;
break;
case CMPD:
srcdst.d -= fregs[fac].d;
ccset = FZ|FN;
break;
case LDEXP:
srcdst.d = 0.0;
srcdst.s = *wptr;
srcdst.s <<= 7;
srcdst.s += 0200;
adjust = SHORT;
ccset = FZ|FN;
#ifdef DEBUG
fprintf(stderr,"LDEXP %o gives %o\n",*wptr,srcdst.s);
#endif
break;
case MODD:
srcdst.d *= fregs[fac].d;
fregs[fac].d = (double)(long)srcdst.d;
if(~fac & 1) fregs[fac + 1].d = fregs[fac].d;
srcdst.d -= fregs[fac].d;
ccset = FN|FZ;
fregs[fac].d = srcdst.d;
#ifdef DEBUG
fprintf(stderr,"MODD %o %o\n",fregs[fac].s,fregs[fac+1].s);
#endif
break;
case STCDL:
if(lng)
adjust = output = LONG;
else
adjust = output = SHORT;
if(mode == 0) output = SHORT;
srcdst.l = fregs[fac].d;
#ifdef DEBUG
fprintf(stderr,"STCDL %o\n",srcdst.l);
#endif
ccset = FZ|FN;
break;
case STEXP:
#ifdef DEBUG
fprintf(stderr,"STEXP of %o gives ",srcdst.s);
#endif
srcdst.s &= 077600;
srcdst.s >>= 7;
srcdst.s -= 0200;
adjust = output = SHORT;
ccset = FZ|FN;
#ifdef DEBUG
fprintf(stderr,"%o\n",srcdst.s);
#endif
break;
default:
return(-1);
}
}
if(ccset & FZ) {
fps &= ~FZ;
if(srcdst.d == 0.0) fps |= FZ;
if(!dbl && srcdst.f == 0.0) fps |= FZ;
}
if(ccset & FN) {
fps &= ~FN;
if(srcdst.f < 0.0) fps |= FN;
}
switch(instr & 0177400) {
case STCDL:
case STEXP:
psl &= ~017;
psl |= (fps & 017);
break;
default:
break;
}
switch(output) {
case NONE:
break;
case SHORT:
*((short *)wptr) = srcdst.s;
srcdst.d = 0.0;
break;
case LONG:
if(mode == 4) wptr--;
*((long *)wptr) = longrev(srcdst.l);
break;
case FLOAT:
if(mode == 4) wptr--;
*((float *)wptr) = srcdst.f;
break;
case DOUBLE:
if(mode == 4) wptr -= 3;
*((double *)wptr) = srcdst.d;
break;
}
switch(mode) {
case 0:
case 1:
break;
case 2:
switch(adjust) {
case SHORT:
regs[ac] += 2;
break;
case LONG:
case FLOAT:
regs[ac] += 4;
break;
case DOUBLE:
regs[ac] += 8;
break;
case NONE:
break;
}
if(ac == 7) pc++;
break;
case 3:
regs[ac] += 2;
if(ac == 7) pc++;
break;
case 4:
switch(adjust) {
case SHORT:
regs[ac] -= 2;
break;
case LONG:
case FLOAT:
regs[ac] -= 4;
break;
case DOUBLE:
regs[ac] -= 8;
break;
case NONE:
break;
}
break;
case 5:
regs[ac] -= 2;
break;
case 6:
case 7:
pc++;
break;
}
return(0);
#endif
}
#ifndef NOFPSIM
unsigned short *locate(mode, ac) {
register unsigned short *wptr;
switch(mode) {
case 0:
/* mode 0 normally implies fregs */
wptr = (unsigned short *)&fregs[ac];
break;
case 1:
break;
case 2:
wptr = (unsigned short *)(int)regs[ac];
break;
case 3:
wptr = (unsigned short *)regs[ac];
wptr = (unsigned short *)*wptr;
break;
case 4:
wptr = (unsigned short *)regs[ac];
wptr--;
break;
case 5:
wptr = (unsigned short *)regs[ac];
wptr--;
wptr = (unsigned short *)*wptr;
break;
case 6:
wptr = (unsigned short *)((regs[ac] + *pc) & 0177776);
if(ac == 7) wptr++;
break;
case 7:
wptr = (unsigned short *)((regs[ac] + *pc) & 0177776);
if(ac == 7) wptr++;
wptr = (unsigned short *)*wptr;
break;
}
return(wptr);
}
#endif