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