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