1*6797Srrh #
2*6797Srrh static char sccsid[] = "	dofloat.c	1.1	82/05/12	";
3*6797Srrh /*
4*6797Srrh  *	Simulate pdp11 floating point for compatability mode programs.
5*6797Srrh  *	Quick and dirty with no big effort at speed since it takes so
6*6797Srrh  *	much overhead to get here in the first place.
7*6797Srrh  *	I make no claims on the completeness of this simulation.
8*6797Srrh  *	Art Wetzel 3/16/80
9*6797Srrh  */
10*6797Srrh #ifndef NOFPSIM
11*6797Srrh #ifdef DEBUG
12*6797Srrh #include <stdio.h>
13*6797Srrh #endif
14*6797Srrh #include "defs.h"
15*6797Srrh /* output codes */
16*6797Srrh #define	NONE	0
17*6797Srrh #define	SHORT	01
18*6797Srrh #define	LONG	02
19*6797Srrh #define	FLOAT	04
20*6797Srrh #define	DOUBLE	010
21*6797Srrh #define	OUTPUT	020
22*6797Srrh /* parts of fps */
23*6797Srrh #define	FD	0200
24*6797Srrh #define	FL	0100
25*6797Srrh #define	FN	010
26*6797Srrh #define	FZ	04
27*6797Srrh #define	FV	02
28*6797Srrh #define	FC	01
29*6797Srrh /* fis instructions */
30*6797Srrh #define	FADD	075000
31*6797Srrh #define	FSUB	075010
32*6797Srrh #define	FMUL	075020
33*6797Srrh #define	FDIV	075030
34*6797Srrh /* fpu instructions */
35*6797Srrh #define	ABSD	0170600
36*6797Srrh #define	ABSF	0170600
37*6797Srrh #define	ADDD	0172000
38*6797Srrh #define	ADDF	0172000
39*6797Srrh #define	CFCC	0170000
40*6797Srrh #define	CLRD	0170400
41*6797Srrh #define	CLRF	0170400
42*6797Srrh #define	CMPD	0173400
43*6797Srrh #define	CMPF	0173400
44*6797Srrh #define	DIVD	0174400
45*6797Srrh #define	DIVF	0174400
46*6797Srrh #define	LDCFD	0177400
47*6797Srrh #define	LDCFF	0177400
48*6797Srrh #define	LDCLD	0177000
49*6797Srrh #define	LDCLF	0177000
50*6797Srrh #define	LDCIF	0177000
51*6797Srrh #define	LDCID	0177000
52*6797Srrh #define	LDEXP	0176400
53*6797Srrh #define	LDD	0172400
54*6797Srrh #define	LDF	0172400
55*6797Srrh #define	LDFPS	0170100
56*6797Srrh #define	MODD	0171400
57*6797Srrh #define	MODF	0171400
58*6797Srrh #define	MULD	0171000
59*6797Srrh #define	MULF	0171000
60*6797Srrh #define	NEGD	0170700
61*6797Srrh #define	NEGF	0170700
62*6797Srrh #define	SETF	0170001
63*6797Srrh #define	SETD	0170011
64*6797Srrh #define	SETI	0170002
65*6797Srrh #define	SETL	0170012
66*6797Srrh #define	STCDF	0176000
67*6797Srrh #define	STCFD	0176000
68*6797Srrh #define	STCDL	0175400
69*6797Srrh #define	STCDI	0175400
70*6797Srrh #define	STCFL	0175400
71*6797Srrh #define	STCFI	0175400
72*6797Srrh #define	STEXP	0175000
73*6797Srrh #define	STD	0174000
74*6797Srrh #define	STF	0174000
75*6797Srrh #define	STFPS	0170200
76*6797Srrh #define	STST	0170300
77*6797Srrh #define	SUBD	0173000
78*6797Srrh #define	SUBF	0173000
79*6797Srrh #define	TSTD	0170500
80*6797Srrh #define	TSTF	0170500
81*6797Srrh union	alltypes	{
82*6797Srrh 	double	d;
83*6797Srrh 	float	f;
84*6797Srrh 	long	l;
85*6797Srrh 	short	s;
86*6797Srrh 	unsigned short p[4];
87*6797Srrh };
88*6797Srrh /* static storage for floating registers */
89*6797Srrh static union	alltypes	fregs[6];
90*6797Srrh static union	alltypes	srcdst;
91*6797Srrh int	fps = FD|FL;
92*6797Srrh int	dbl = 0;
93*6797Srrh int	lng = 0;
94*6797Srrh #endif
95*6797Srrh dofloat(instr) unsigned int instr; {
96*6797Srrh #ifdef NOFPSIM
97*6797Srrh 	return(-1);
98*6797Srrh #else
99*6797Srrh 	register unsigned short *wptr;
100*6797Srrh 	register unsigned int opcode, ac, mode, fac, adjust, output, ccset;
101*6797Srrh 	unsigned short *locate();
102*6797Srrh 	/* indicate what condition codes will be changed by op - assume none */
103*6797Srrh 	ccset = 0;
104*6797Srrh 	/* type of memory output - assume none */
105*6797Srrh 	output = NONE;
106*6797Srrh 	/* default adjust to type */
107*6797Srrh 	if(dbl)
108*6797Srrh 		adjust = DOUBLE;
109*6797Srrh 	else
110*6797Srrh 		adjust = FLOAT;
111*6797Srrh 	/* chop up instruction to get relevent parts */
112*6797Srrh 	opcode = instr & 0177700;
113*6797Srrh 	fac = (instr>>6) & 03;
114*6797Srrh 	mode = (instr>>3) & 07;
115*6797Srrh 	ac = instr & 07;
116*6797Srrh 	/* if the instruction uses a src/dst construct ptr and fetch */
117*6797Srrh 	switch(opcode) {
118*6797Srrh 	case	FADD:
119*6797Srrh 	case	CFCC:
120*6797Srrh 		break;
121*6797Srrh 	default:
122*6797Srrh 		wptr = locate(mode, ac);
123*6797Srrh 		/* special case for mode 0 */
124*6797Srrh 		if(mode == 0) switch(opcode & 0177400) {
125*6797Srrh 		/* special instructions to use cpu regs */
126*6797Srrh 		case	LDEXP:
127*6797Srrh 		case	STEXP:
128*6797Srrh 			wptr = &regs[ac];
129*6797Srrh 			break;
130*6797Srrh 		case	STCDL:
131*6797Srrh 			wptr = &regs[ac];
132*6797Srrh 		default:
133*6797Srrh 			break;
134*6797Srrh 		}
135*6797Srrh 		if(dbl)
136*6797Srrh 			srcdst.d = *(double *)wptr;
137*6797Srrh 		else
138*6797Srrh 			srcdst.f = *(float *)wptr;
139*6797Srrh 		/* immediate fetches are 16 bits */
140*6797Srrh 		if(ac == 7 && (mode == 2)) {
141*6797Srrh 			srcdst.p[1] = 0;
142*6797Srrh 			srcdst.p[2] = 0;
143*6797Srrh 			srcdst.p[3] = 0;
144*6797Srrh 		}
145*6797Srrh 		break;
146*6797Srrh 	}
147*6797Srrh #ifdef	DEBUG
148*6797Srrh 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);
149*6797Srrh #endif
150*6797Srrh 	switch(opcode) {
151*6797Srrh 	case	FADD:
152*6797Srrh 		/* catches all fis instructions */
153*6797Srrh 		/* last 3 bits are stack pointer register */
154*6797Srrh 		ac = instr & 07;
155*6797Srrh 		/* get pointer to stack words */
156*6797Srrh 		wptr = (unsigned short *)regs[ac];
157*6797Srrh 		/* getch floating value from stack */
158*6797Srrh 		srcdst.f = *(float *)wptr;
159*6797Srrh 		/* shorten stack */
160*6797Srrh 		wptr += 2;
161*6797Srrh 		/* do appropriate operation */
162*6797Srrh 		switch(instr & 0177770) {
163*6797Srrh 		case	FADD:
164*6797Srrh 			srcdst.f += *(float *)wptr;
165*6797Srrh 			break;
166*6797Srrh 		case	FSUB:
167*6797Srrh 			srcdst.f = *(float *)wptr - srcdst.f;
168*6797Srrh 			break;
169*6797Srrh 		case	FMUL:
170*6797Srrh 			srcdst.f *= *(float *)wptr;
171*6797Srrh 			break;
172*6797Srrh 		case	FDIV:
173*6797Srrh 			srcdst.f = *(float *)wptr / srcdst.f;
174*6797Srrh 			break;
175*6797Srrh 		default:
176*6797Srrh 			return(-1);
177*6797Srrh 		}
178*6797Srrh 		/* copy out result */
179*6797Srrh 		*(float *)wptr = srcdst.f;
180*6797Srrh 		/* set up condition codes */
181*6797Srrh 		psl &= ~017;
182*6797Srrh 		if(srcdst.f == 0.) psl |= FZ;
183*6797Srrh 		if(srcdst.f < 0.) psl |= FN;
184*6797Srrh 		/* adjust register to reflect stack change */
185*6797Srrh 		regs[ac] = (unsigned short)(int)wptr;
186*6797Srrh 		return(0);
187*6797Srrh 	case	CFCC:
188*6797Srrh 		switch(instr) {
189*6797Srrh 		case	SETF:
190*6797Srrh 			dbl = 0;
191*6797Srrh 			break;
192*6797Srrh 		case	SETD:
193*6797Srrh 			dbl = 1;
194*6797Srrh 			break;
195*6797Srrh 		case	SETI:
196*6797Srrh 			lng = 0;
197*6797Srrh 			break;
198*6797Srrh 		case	SETL:
199*6797Srrh 			lng = 1;
200*6797Srrh 			break;
201*6797Srrh 		case	CFCC:
202*6797Srrh 			psl &= ~017;
203*6797Srrh 			psl |= (fps & 017);
204*6797Srrh #ifdef DEBUG
205*6797Srrh fprintf(stderr,"CFCC %o\n",psl);
206*6797Srrh #endif
207*6797Srrh 			break;
208*6797Srrh 		default:
209*6797Srrh 			return(-1);
210*6797Srrh 		}
211*6797Srrh 		return(0);
212*6797Srrh 	case	ABSD:
213*6797Srrh 		if(srcdst.d < 0.0 ) srcdst.d = -srcdst.d;
214*6797Srrh 		ccset = FZ;
215*6797Srrh 		if(dbl)
216*6797Srrh 			output = DOUBLE;
217*6797Srrh 		else
218*6797Srrh 			output = FLOAT;
219*6797Srrh 		break;
220*6797Srrh 	case	CLRD:
221*6797Srrh 		srcdst.d =0.0;
222*6797Srrh 		ccset = FZ;
223*6797Srrh 		if(dbl)
224*6797Srrh 			output = DOUBLE;
225*6797Srrh 		else
226*6797Srrh 			output = FLOAT;
227*6797Srrh 		break;
228*6797Srrh 	case	LDFPS:
229*6797Srrh 		adjust = SHORT;
230*6797Srrh 		fps = srcdst.s;
231*6797Srrh 		if(fps & FD)
232*6797Srrh 			dbl = 1;
233*6797Srrh 		else
234*6797Srrh 			dbl = 0;
235*6797Srrh 		if(fps & FL )
236*6797Srrh 			lng = 1;
237*6797Srrh 		else
238*6797Srrh 			lng = 0;
239*6797Srrh 		break;
240*6797Srrh 	case	NEGD:
241*6797Srrh 		srcdst.d = -srcdst.d;
242*6797Srrh 		ccset = FZ|FN;
243*6797Srrh 		if(dbl)
244*6797Srrh 			output = DOUBLE;
245*6797Srrh 		else
246*6797Srrh 			output = FLOAT;
247*6797Srrh 		break;
248*6797Srrh 	case	STFPS:
249*6797Srrh 		srcdst.s = fps;
250*6797Srrh 		adjust = output = SHORT;
251*6797Srrh 		break;
252*6797Srrh 	case	STST:
253*6797Srrh 		return(0);
254*6797Srrh 		break;
255*6797Srrh 	case	TSTD:
256*6797Srrh 		ccset = FZ|FN;
257*6797Srrh 		break;
258*6797Srrh 	default:
259*6797Srrh 		opcode = instr & 0177400;
260*6797Srrh 		switch(opcode) {
261*6797Srrh 		case	STD:
262*6797Srrh 			srcdst.d = fregs[fac].d;
263*6797Srrh #ifdef DEBUG
264*6797Srrh fprintf(stderr,"STD %o\n",srcdst.s);
265*6797Srrh #endif
266*6797Srrh 			if(dbl)
267*6797Srrh 				output = DOUBLE;
268*6797Srrh 			else
269*6797Srrh 				output = FLOAT;
270*6797Srrh 			break;
271*6797Srrh 		case	LDD:
272*6797Srrh #ifdef DEBUG
273*6797Srrh fprintf(stderr,"LDD %o\n",srcdst.s);
274*6797Srrh #endif
275*6797Srrh 			fregs[fac].d = srcdst.d;
276*6797Srrh 			ccset = FZ|FN;
277*6797Srrh 			break;
278*6797Srrh 		case	ADDD:
279*6797Srrh 			fregs[fac].d += srcdst.d;
280*6797Srrh 			ccset = FZ|FN;
281*6797Srrh 			break;
282*6797Srrh 		case	SUBD:
283*6797Srrh 			fregs[fac].d -= srcdst.d;
284*6797Srrh 			ccset = FZ|FN;
285*6797Srrh 			break;
286*6797Srrh 		case	MULD:
287*6797Srrh 			fregs[fac].d *= srcdst.d;
288*6797Srrh 			ccset = FZ|FN;
289*6797Srrh 			break;
290*6797Srrh 		case	DIVD:
291*6797Srrh #ifdef DEBUG
292*6797Srrh fprintf(stderr,"DIVD %f by %f gives ",fregs[fac].d,srcdst.d);
293*6797Srrh #endif
294*6797Srrh 			fregs[fac].d /= srcdst.d;
295*6797Srrh #ifdef DEBUG
296*6797Srrh fprintf(stderr,"-> %f\n",fregs[fac].d);
297*6797Srrh #endif
298*6797Srrh 			ccset = FZ|FN;
299*6797Srrh 			break;
300*6797Srrh 		case	STCDF:
301*6797Srrh 			adjust = output = FLOAT;
302*6797Srrh 			ccset = FZ|FN;
303*6797Srrh 			break;
304*6797Srrh 		case	LDCFD:
305*6797Srrh 			adjust = FLOAT;
306*6797Srrh 			ccset = FZ|FN;
307*6797Srrh 			break;
308*6797Srrh 		case	LDCLD:
309*6797Srrh 			if(lng) {
310*6797Srrh 				adjust = LONG;
311*6797Srrh 				srcdst.d = srcdst.l;
312*6797Srrh 			} else {
313*6797Srrh 				adjust = SHORT;
314*6797Srrh 				srcdst.d = srcdst.s;
315*6797Srrh 			}
316*6797Srrh 			ccset = FZ|FN;
317*6797Srrh 			break;
318*6797Srrh 		case	CMPD:
319*6797Srrh 			srcdst.d -= fregs[fac].d;
320*6797Srrh 			ccset = FZ|FN;
321*6797Srrh 			break;
322*6797Srrh 		case	LDEXP:
323*6797Srrh 			srcdst.d = 0.0;
324*6797Srrh 			srcdst.s = *wptr;
325*6797Srrh 			srcdst.s <<= 7;
326*6797Srrh 			srcdst.s += 0200;
327*6797Srrh 			adjust = SHORT;
328*6797Srrh 			ccset = FZ|FN;
329*6797Srrh #ifdef	DEBUG
330*6797Srrh fprintf(stderr,"LDEXP %o gives %o\n",*wptr,srcdst.s);
331*6797Srrh #endif
332*6797Srrh 			break;
333*6797Srrh 		case	MODD:
334*6797Srrh 			srcdst.d *= fregs[fac].d;
335*6797Srrh 			fregs[fac].d = (double)(long)srcdst.d;
336*6797Srrh 			if(~fac & 1) fregs[fac + 1].d = fregs[fac].d;
337*6797Srrh 			srcdst.d -= fregs[fac].d;
338*6797Srrh 			ccset = FN|FZ;
339*6797Srrh 			fregs[fac].d = srcdst.d;
340*6797Srrh #ifdef DEBUG
341*6797Srrh fprintf(stderr,"MODD %o %o\n",fregs[fac].s,fregs[fac+1].s);
342*6797Srrh #endif
343*6797Srrh 			break;
344*6797Srrh 		case	STCDL:
345*6797Srrh 			if(lng)
346*6797Srrh 				adjust = output = LONG;
347*6797Srrh 			else
348*6797Srrh 				adjust = output = SHORT;
349*6797Srrh 			if(mode == 0) output = SHORT;
350*6797Srrh 			srcdst.l = fregs[fac].d;
351*6797Srrh #ifdef DEBUG
352*6797Srrh fprintf(stderr,"STCDL %o\n",srcdst.l);
353*6797Srrh #endif
354*6797Srrh 			ccset = FZ|FN;
355*6797Srrh 			break;
356*6797Srrh 		case	STEXP:
357*6797Srrh #ifdef DEBUG
358*6797Srrh fprintf(stderr,"STEXP of %o gives ",srcdst.s);
359*6797Srrh #endif
360*6797Srrh 			srcdst.s &= 077600;
361*6797Srrh 			srcdst.s >>= 7;
362*6797Srrh 			srcdst.s -= 0200;
363*6797Srrh 			adjust = output = SHORT;
364*6797Srrh 			ccset = FZ|FN;
365*6797Srrh #ifdef DEBUG
366*6797Srrh fprintf(stderr,"%o\n",srcdst.s);
367*6797Srrh #endif
368*6797Srrh 			break;
369*6797Srrh 		default:
370*6797Srrh 			return(-1);
371*6797Srrh 		}
372*6797Srrh 	}
373*6797Srrh 	if(ccset & FZ) {
374*6797Srrh 		fps &= ~FZ;
375*6797Srrh 		if(srcdst.d == 0.0) fps |= FZ;
376*6797Srrh 		if(!dbl && srcdst.f == 0.0) fps |= FZ;
377*6797Srrh 	}
378*6797Srrh 	if(ccset & FN) {
379*6797Srrh 		fps &= ~FN;
380*6797Srrh 		if(srcdst.f < 0.0) fps |= FN;
381*6797Srrh 	}
382*6797Srrh 	switch(instr & 0177400) {
383*6797Srrh 	case	STCDL:
384*6797Srrh 	case	STEXP:
385*6797Srrh 		psl &= ~017;
386*6797Srrh 		psl |= (fps & 017);
387*6797Srrh 		break;
388*6797Srrh 	default:
389*6797Srrh 		break;
390*6797Srrh 	}
391*6797Srrh 	switch(output) {
392*6797Srrh 	case	NONE:
393*6797Srrh 		break;
394*6797Srrh 	case	SHORT:
395*6797Srrh 		*((short *)wptr) = srcdst.s;
396*6797Srrh 		srcdst.d = 0.0;
397*6797Srrh 		break;
398*6797Srrh 	case	LONG:
399*6797Srrh 		if(mode == 4) wptr--;
400*6797Srrh 		*((long *)wptr) = longrev(srcdst.l);
401*6797Srrh 		break;
402*6797Srrh 	case	FLOAT:
403*6797Srrh 		if(mode == 4) wptr--;
404*6797Srrh 		*((float *)wptr) = srcdst.f;
405*6797Srrh 		break;
406*6797Srrh 	case	DOUBLE:
407*6797Srrh 		if(mode == 4) wptr -= 3;
408*6797Srrh 		*((double *)wptr) = srcdst.d;
409*6797Srrh 		break;
410*6797Srrh 	}
411*6797Srrh 	switch(mode) {
412*6797Srrh 	case	0:
413*6797Srrh 	case	1:
414*6797Srrh 		break;
415*6797Srrh 	case	2:
416*6797Srrh 		switch(adjust) {
417*6797Srrh 		case	SHORT:
418*6797Srrh 			regs[ac] += 2;
419*6797Srrh 			break;
420*6797Srrh 		case	LONG:
421*6797Srrh 		case	FLOAT:
422*6797Srrh 			regs[ac] += 4;
423*6797Srrh 			break;
424*6797Srrh 		case	DOUBLE:
425*6797Srrh 			regs[ac] += 8;
426*6797Srrh 			break;
427*6797Srrh 		case	NONE:
428*6797Srrh 			break;
429*6797Srrh 		}
430*6797Srrh 		if(ac == 7) pc++;
431*6797Srrh 		break;
432*6797Srrh 	case	3:
433*6797Srrh 		regs[ac] += 2;
434*6797Srrh 		if(ac == 7) pc++;
435*6797Srrh 		break;
436*6797Srrh 	case	4:
437*6797Srrh 		switch(adjust) {
438*6797Srrh 		case	SHORT:
439*6797Srrh 			regs[ac] -= 2;
440*6797Srrh 			break;
441*6797Srrh 		case	LONG:
442*6797Srrh 		case	FLOAT:
443*6797Srrh 			regs[ac] -= 4;
444*6797Srrh 			break;
445*6797Srrh 		case	DOUBLE:
446*6797Srrh 			regs[ac] -= 8;
447*6797Srrh 			break;
448*6797Srrh 		case	NONE:
449*6797Srrh 			break;
450*6797Srrh 		}
451*6797Srrh 		break;
452*6797Srrh 	case	5:
453*6797Srrh 		regs[ac] -= 2;
454*6797Srrh 		break;
455*6797Srrh 	case	6:
456*6797Srrh 	case	7:
457*6797Srrh 		pc++;
458*6797Srrh 		break;
459*6797Srrh 	}
460*6797Srrh 	return(0);
461*6797Srrh #endif
462*6797Srrh }
463*6797Srrh #ifndef NOFPSIM
464*6797Srrh unsigned short *locate(mode, ac) {
465*6797Srrh 	register unsigned short *wptr;
466*6797Srrh 	switch(mode) {
467*6797Srrh 	case	0:
468*6797Srrh 		/* mode 0 normally implies fregs */
469*6797Srrh 		wptr = (unsigned short *)&fregs[ac];
470*6797Srrh 		break;
471*6797Srrh 	case	1:
472*6797Srrh 		break;
473*6797Srrh 	case	2:
474*6797Srrh 		wptr = (unsigned short *)(int)regs[ac];
475*6797Srrh 		break;
476*6797Srrh 	case	3:
477*6797Srrh 		wptr = (unsigned short *)regs[ac];
478*6797Srrh 		wptr = (unsigned short *)*wptr;
479*6797Srrh 		break;
480*6797Srrh 	case	4:
481*6797Srrh 		wptr = (unsigned short *)regs[ac];
482*6797Srrh 		wptr--;
483*6797Srrh 		break;
484*6797Srrh 	case	5:
485*6797Srrh 		wptr = (unsigned short *)regs[ac];
486*6797Srrh 		wptr--;
487*6797Srrh 		wptr = (unsigned short *)*wptr;
488*6797Srrh 		break;
489*6797Srrh 	case	6:
490*6797Srrh 		wptr = (unsigned short *)((regs[ac] + *pc) & 0177776);
491*6797Srrh 		if(ac == 7) wptr++;
492*6797Srrh 		break;
493*6797Srrh 	case	7:
494*6797Srrh 		wptr = (unsigned short *)((regs[ac] + *pc) & 0177776);
495*6797Srrh 		if(ac == 7) wptr++;
496*6797Srrh 		wptr = (unsigned short *)*wptr;
497*6797Srrh 		break;
498*6797Srrh 	}
499*6797Srrh 	return(wptr);
500*6797Srrh }
501*6797Srrh #endif
502