Commit | Line | Data |
---|---|---|
cf108512 | 1 | # |
c6dd5f9e | 2 | static char sccsid[] = " dofloat.c 4.1 82/05/12 "; |
cf108512 RH |
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 = ®s[ac]; | |
129 | break; | |
130 | case STCDL: | |
131 | wptr = ®s[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 |