|
|
1.1.1.2 ! root 1: * $NetBSD: README,v 1.7 2021/08/21 23:00:31 andvar Exp $ 1.1 root 2: * NetBSD/m68k FPE (floating point emulation) README file 3: * Created Oct/??/95 by [email protected] (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 1.1.1.2 ! root 119: fetch the operands by yourself in your emulation function. For 1.1 root 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.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.