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 = ®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 502