README revision 1.1
11.1Sbriggs* NetBSD/m68k FPE (floating point emulation) README file 21.1Sbriggs* Created Oct/??/95 by kenn@romulus.rutgers.edu (Ken Nakata) 31.1Sbriggs* Last updated Nov/02/95 by kenn 41.1Sbriggs 51.1Sbriggs1. INSTALLATION AND COMPILATION 61.1Sbriggs 71.1SbriggsTo compile a kernel with FPE built-in, do the following: 81.1Sbriggs 91.1Sbriggs1) Extract all files in the directory ${MYSYS}/arch/m68k/fpe 101.1Sbriggs 111.1Sbriggs2) Add a line "options FPU_EMULATE" to your config file. If you are 121.1Sbriggsgoing to use the resulted kernel on a machine with an FPU for 131.1Sbriggsdebugging purpose, add "options DEBUG_WITH_FPU" as well. 141.1Sbriggs 151.1Sbriggs3) Follow the usual procedure to build a new kernel. 161.1Sbriggs 171.1SbriggsNOTE: If you add "options DEBUG_WITH_FPU", FPE will accept cpID=6 as 181.1Sbriggsemulated FPU. You will need a modified gas that generates cpID=6 for 191.1Sbriggsfloating point instructions, instead of normal cpID=1. Mount unionfs 201.1Sbriggsor copy the gas source directory as you did with the kernel source tree, 211.1Sbriggsand apply the following patch: 221.1Sbriggs 231.1Sbriggs*** /usr/src/gnu/usr.bin/gas/config/tc-m68k.c Mon Nov 21 16:30:41 1994 241.1Sbriggs--- gas/config/tc-m68k.c Fri Sep 29 07:59:06 1995 251.1Sbriggs*************** 261.1Sbriggs*** 1275,1281 **** 271.1Sbriggs /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */ 281.1Sbriggs memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0])); 291.1Sbriggs the_ins.operands[0].mode=MSCR; 301.1Sbriggs! the_ins.operands[0].reg=COPNUM; /* COP #1 */ 311.1Sbriggs opsfound++; 321.1Sbriggs } 331.1Sbriggs 341.1Sbriggs--- 1275,1281 ---- 351.1Sbriggs /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */ 361.1Sbriggs memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0])); 371.1Sbriggs the_ins.operands[0].mode=MSCR; 381.1Sbriggs! the_ins.operands[0].reg=COP5; /* COP #6 */ 391.1Sbriggs opsfound++; 401.1Sbriggs } 411.1Sbriggs 421.1Sbriggs 431.1SbriggsAlso, with the DEBUG_WITH_FPU option, you will be able to run only ONE 441.1Sbriggsprocess that uses FPE at once to get correct results. 451.1Sbriggs 461.1Sbriggs 471.1Sbriggs2. MISSING PARTS 481.1Sbriggs 491.1SbriggsFor missing instructions, refer to the Section 3. Other than that, 501.1Sbriggsthere is one thing that is missing from this version of FPE: packed 511.1SbriggsBCD support. 521.1Sbriggs 531.1SbriggsI have no plan to support it since it's rarely used. However, all we 541.1Sbriggsneed to support it is explosion/implosion functions between the 551.1Sbriggsinternal FP representation and the m68k PBCD format, so you are more 561.1Sbriggsthan welcome to write such functions if you wish to. 571.1Sbriggs 581.1Sbriggs 591.1Sbriggs3. IMPLEMENTED INSTRUCTIONS 601.1Sbriggs 611.1SbriggsThis is the list of implemented and unimplemented FPU instructions. 621.1SbriggsMost 040's directly supported type 0 instructions are already 631.1Sbriggsimplemented except FSGLDIV, FSGLMUL, FMOVE(M) FPcr, and FMOVECR. 641.1Sbriggs 651.1SbriggsType field = bit 8-6 of opcode word 661.1Sbriggs 671.1Sbriggs* Implemented Instructions 681.1Sbriggs 691.1SbriggsType=0: FMOVE (mem->FPr), FINT, FINTRZ, FSQRT, FABS, FNEG, FGETEXP, 701.1Sbriggs FGETMAN, FDIV, FADD, FMUL, FSGLDIV, FSCALE, FSGLMUL, FSUB, 711.1Sbriggs FCMP, FTST, FMOVE (FPr->mem), FMOVEM (FPr), FMOVEM (FPcr), 721.1Sbriggs FMOVECR, FLOGNP1, FLOGN, FLOG10, FLOG2, FMOD, FREM 731.1Sbriggs 741.1SbriggsType=1: FDBcc, FScc, FTRAPcc, 751.1Sbriggs 761.1SbriggsType=2: FBcc (word, incl. FNOP) 771.1Sbriggs 781.1SbriggsType=3: FBcc (long) 791.1Sbriggs 801.1SbriggsType=4: none 811.1Sbriggs 821.1SbriggsType=5: none 831.1Sbriggs 841.1Sbriggs *: currently FSGLMUL and FSGLDIV are just aliases of 851.1Sbriggs FMUL and FDIV, respectively 861.1Sbriggs 871.1Sbriggs* Unimplemented Instructions 881.1Sbriggs 891.1SbriggsType=0: FSINH, FETOXM1, FTANH, FATAN, FASIN, FATANH, FSIN, FTAN, 901.1Sbriggs FETOX, FTWOTOX, FTENTOX, FCOSH, FACOS, FCOS, FSINCOS 911.1Sbriggs 921.1SbriggsType=1: none 931.1Sbriggs 941.1SbriggsType=2: none 951.1Sbriggs 961.1SbriggsType=3: none 971.1Sbriggs 981.1SbriggsType=4: FSAVE 991.1Sbriggs 1001.1SbriggsType=5: FRESTORE 1011.1Sbriggs 1021.1Sbriggs 1031.1Sbriggs4. HOW TO ADD A NEW INSTRUCTION SUPPORT 1041.1Sbriggs 1051.1SbriggsSince we need not support FSAVE and FRESTORE operations, all 1061.1Sbriggsinstructions we have to implement are type 0, all of which are 1071.1Sbriggsarithmetic operations. It is particularly easy to add a new 1081.1Sbriggsarithmetic instruction to the existing ones (not that it is easy to 1091.1Sbriggswrite a "stable" function to perform floating point operation. That's 1101.1Sbriggsentirely another matter). In "fpu_emulate.c", there's a function 1111.1Sbriggsfpu_emul_arith() which calls emulation functions for all arithmetic 1121.1Sbriggsoperations. In it, there's a large switch() { case ... } which 1131.1Sbriggsdispatches each instruction emulator. An emulation function of any 1141.1Sbriggstype 0 arithmetic instruction follows this prototype: 1151.1Sbriggs 1161.1Sbriggs struct fpn *fpu_op(struct fpemu *fe); 1171.1Sbriggs 1181.1SbriggsWhere fe is a pointer to a struct fpemu in which frame, fpframe, and 1191.1Sbriggsfetched operands are accessible. That's right, you don't have to 1201.1Sbriggsfetch the operands by yourself in your emulation funtion. For 1211.1Sbriggsinstance, the parts calling FSQRT, FSUB, FADD and FTST look like: 1221.1Sbriggs 1231.1Sbriggs switch(word1 & 0x3F) { 1241.1Sbriggs[...] 1251.1Sbriggs case 0x04: /* fsqrt */ 1261.1Sbriggs res = fpu_sqrt(fe); 1271.1Sbriggs break; 1281.1Sbriggs[...] 1291.1Sbriggs case 0x28: /* fsub */ 1301.1Sbriggs fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */ 1311.1Sbriggs case 0x22: /* fadd */ 1321.1Sbriggs res = fpu_add(fe); 1331.1Sbriggs break; 1341.1Sbriggs[...] 1351.1Sbriggs case 0x3A: /* ftst */ 1361.1Sbriggs res = &fe->fe_f2; 1371.1Sbriggs no_store = 1; 1381.1Sbriggs break; 1391.1Sbriggs[...] 1401.1Sbriggs default: 1411.1Sbriggs sig = SIGILL; 1421.1Sbriggs } /* switch */ 1431.1Sbriggs 1441.1SbriggsHere, fe->fe_f1 and fe->fe_f2 are fetched operands. You can use 1451.1Sbriggsfe->fe_f3 for storing the result, or you can return a pointer to 1461.1Sbriggseither operand if you want to. At any rate, you have to follow 1471.1Sbriggsthe following rules: 1481.1Sbriggs 1491.1Sbriggs 1) A dyadic instruction takes two operands fe->fe_f1 and fe->fe_f2. 1501.1Sbriggs 2) A monadic instruction takes one operands fe->fe_f2 (NOT fe_f1). 1511.1Sbriggs 3) Must return a pointer to struct fpn where the result is stored, 1521.1Sbriggs and assign the pointer to the variable "res". 1531.1Sbriggs 4) If exceptions are detected, set corresponding bits in fe->fe_fpsr. 1541.1Sbriggs The rest is taken care of in fpu_emul_arith(). 1551.1Sbriggs 5) Condition code need not be calculated. It's taken care of in 1561.1Sbriggs fpu_emul_arith(). 1571.1Sbriggs 1581.1SbriggsIt's easy to interface, isn't it? 1591.1Sbriggs 1601.1Sbriggs* Actually, after above was written, stubs for the missing functions 1611.1Sbriggsare added to the source, so you do not have to change fpu_emul_arith() 1621.1Sbriggsat all. Function names and prototypes are in fpu_arith_proto.h, and 1631.1Sbriggsall (except fpu_sincos()) follows the rules above. 1641.1Sbriggs 165