1 * $NetBSD: README,v 1.7 2021/08/21 23:00:31 andvar Exp $ 2 * NetBSD/m68k FPE (floating point emulation) README file 3 * Created Oct/??/95 by kenn (a] remus.rutgers.edu (Ken Nakata) 4 * Last updated Oct/15/2011 by tsutsui 5 6 1. INSTALLATION AND COMPILATION 7 8 To compile a kernel with FPE built-in, do the following: 9 10 1) Add a line "options FPU_EMULATE" to your config file. If you are 11 going to use the resulted kernel on a machine with an FPU for 12 debugging purpose, add "options DEBUG_WITH_FPU" as well. 13 14 2) Follow the usual procedure to build a new kernel. 15 16 NOTE: If you add "options DEBUG_WITH_FPU", FPE will accept cpID=6 as 17 emulated FPU. You will need a modified gas that generates cpID=6 for 18 floating point instructions, instead of normal cpID=1. Mount unionfs 19 or copy the gas source directory and apply the following patch: 20 21 *** /usr/src/gnu/usr.bin/gas/config/tc-m68k.c Mon Nov 21 16:30:41 1994 22 --- gas/config/tc-m68k.c Fri Sep 29 07:59:06 1995 23 *************** 24 *** 1275,1281 **** 25 /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */ 26 memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0])); 27 the_ins.operands[0].mode=MSCR; 28 ! the_ins.operands[0].reg=COPNUM; /* COP #1 */ 29 opsfound++; 30 } 31 32 --- 1275,1281 ---- 33 /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */ 34 memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0])); 35 the_ins.operands[0].mode=MSCR; 36 ! the_ins.operands[0].reg=COP5; /* COP #6 */ 37 opsfound++; 38 } 39 40 41 Also, with the DEBUG_WITH_FPU option, you will be able to run only ONE 42 process that uses FPE at once to get correct results. 43 44 45 2. MISSING PARTS 46 47 For missing instructions, refer to the Section 3. Other than that, 48 there is one thing that is missing from this version of FPE: packed 49 BCD support. 50 51 I have no plan to support it since it's rarely used. However, all we 52 need to support it is explosion/implosion functions between the 53 internal FP representation and the m68k PBCD format, so you are more 54 than welcome to write such functions if you wish to. 55 56 57 3. IMPLEMENTED INSTRUCTIONS 58 59 This is the list of implemented and unimplemented FPU instructions. 60 All 040's directly supported type 0 instructions are already 61 implemented except FSGLDIV and FSGLMUL. 62 63 Type field = bit 8-6 of opcode word 64 65 * Implemented Instructions 66 67 Type=0: FMOVE (mem->FPr), FINT, FINTRZ, FSQRT, FABS, FNEG, FGETEXP, 68 FGETMAN, FDIV, FADD, FMUL, FSGLDIV(*), FSCALE, FSGLMUL(*), FSUB, 69 FCMP, FTST, FMOVE (FPr->mem), FMOVEM (FPr), FMOVEM (FPcr), 70 FMOVECR, FLOGNP1, FLOGN, FLOG10, FLOG2, FMOD, FREM, 71 FCOSH, FSINH, FTANH, FCOS, FSIN, FTAN, FSINCOS, 72 FETOX, FETOXM1, FTENTOX, FTWOTOX, FATANH, FACOS, FASIN, FATAN 73 74 Type=1: FDBcc, FScc, FTRAPcc, 75 76 Type=2: FBcc (word, incl. FNOP) 77 78 Type=3: FBcc (long) 79 80 Type=4: none 81 82 Type=5: none 83 84 *: currently FSGLMUL and FSGLDIV are just aliases of 85 FMUL and FDIV, respectively 86 87 * Unimplemented Instructions 88 89 Type=0: none 90 91 Type=1: none 92 93 Type=2: none 94 95 Type=3: none 96 97 Type=4: FSAVE 98 99 Type=5: FRESTORE 100 101 102 4. HOW TO ADD A NEW INSTRUCTION SUPPORT 103 104 Since we need not support FSAVE and FRESTORE operations, all 105 instructions we have to implement are type 0, all of which are 106 arithmetic operations. It is particularly easy to add a new 107 arithmetic instruction to the existing ones (not that it is easy to 108 write a "stable" function to perform floating point operation. That's 109 entirely another matter). In "fpu_emulate.c", there's a function 110 fpu_emul_arith() which calls emulation functions for all arithmetic 111 operations. In it, there's a large switch() { case ... } which 112 dispatches each instruction emulator. An emulation function of any 113 type 0 arithmetic instruction follows this prototype: 114 115 struct fpn *fpu_op(struct fpemu *fe); 116 117 Where fe is a pointer to a struct fpemu in which frame, fpframe, and 118 fetched operands are accessible. That's right, you don't have to 119 fetch the operands by yourself in your emulation function. For 120 instance, the parts calling FSQRT, FSUB, FADD and FTST look like: 121 122 switch(word1 & 0x3F) { 123 [...] 124 case 0x04: /* fsqrt */ 125 res = fpu_sqrt(fe); 126 break; 127 [...] 128 case 0x28: /* fsub */ 129 fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */ 130 case 0x22: /* fadd */ 131 res = fpu_add(fe); 132 break; 133 [...] 134 case 0x3A: /* ftst */ 135 res = &fe->fe_f2; 136 no_store = 1; 137 break; 138 [...] 139 default: 140 sig = SIGILL; 141 } /* switch */ 142 143 Here, fe->fe_f1 and fe->fe_f2 are fetched operands. You can use 144 fe->fe_f3 for storing the result, or you can return a pointer to 145 either operand if you want to. At any rate, you have to follow 146 the following rules: 147 148 1) A dyadic instruction takes two operands fe->fe_f1 and fe->fe_f2. 149 2) A monadic instruction takes one operands fe->fe_f2 (NOT fe_f1). 150 3) Must return a pointer to struct fpn where the result is stored, 151 and assign the pointer to the variable "res". 152 4) If exceptions are detected, set corresponding bits in fe->fe_fpsr. 153 The rest is taken care of in fpu_emul_arith(). 154 5) Condition code need not be calculated. It's taken care of in 155 fpu_emul_arith(). 156 157 Actually, after above was written, stubs for the missing functions were 158 added to the source, so you do not have to change fpu_emul_arith() at 159 all. Function names and prototypes are in fpu_arith_proto.h, and all 160 except fpu_sincos() follow the rules above. fpu_sincos() is declared 161 as 162 163 struct fpn *fpu_sincos(struct fpemu *fe, int cosreg); 164 165 where cosreg is the FP register number to which cosine of the argument 166 is calculated and assigned. Sine of the argument is stored into the 167 destination register in the same manner as the other arithmetic 168 functions. 169