README revision 1.5 1 1.5 tsutsui * $NetBSD: README,v 1.5 2011/10/15 15:24:28 tsutsui 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.5 tsutsui FCOSH, FSINH, FTANH, FCOS, FSIN, FTAN, FSINCOS
72 1.1 briggs
73 1.1 briggs Type=1: FDBcc, FScc, FTRAPcc,
74 1.1 briggs
75 1.1 briggs Type=2: FBcc (word, incl. FNOP)
76 1.1 briggs
77 1.1 briggs Type=3: FBcc (long)
78 1.1 briggs
79 1.1 briggs Type=4: none
80 1.1 briggs
81 1.1 briggs Type=5: none
82 1.1 briggs
83 1.1 briggs *: currently FSGLMUL and FSGLDIV are just aliases of
84 1.1 briggs FMUL and FDIV, respectively
85 1.1 briggs
86 1.1 briggs * Unimplemented Instructions
87 1.1 briggs
88 1.5 tsutsui Type=0: FETOX, FETOXM1, FTENTOX, FTWOTOX, FATANH, FACOS, FASIN, FATAN
89 1.1 briggs
90 1.1 briggs Type=1: none
91 1.1 briggs
92 1.1 briggs Type=2: none
93 1.1 briggs
94 1.1 briggs Type=3: none
95 1.1 briggs
96 1.1 briggs Type=4: FSAVE
97 1.1 briggs
98 1.1 briggs Type=5: FRESTORE
99 1.1 briggs
100 1.1 briggs
101 1.1 briggs 4. HOW TO ADD A NEW INSTRUCTION SUPPORT
102 1.1 briggs
103 1.1 briggs Since we need not support FSAVE and FRESTORE operations, all
104 1.1 briggs instructions we have to implement are type 0, all of which are
105 1.1 briggs arithmetic operations. It is particularly easy to add a new
106 1.1 briggs arithmetic instruction to the existing ones (not that it is easy to
107 1.1 briggs write a "stable" function to perform floating point operation. That's
108 1.1 briggs entirely another matter). In "fpu_emulate.c", there's a function
109 1.1 briggs fpu_emul_arith() which calls emulation functions for all arithmetic
110 1.1 briggs operations. In it, there's a large switch() { case ... } which
111 1.1 briggs dispatches each instruction emulator. An emulation function of any
112 1.1 briggs type 0 arithmetic instruction follows this prototype:
113 1.1 briggs
114 1.1 briggs struct fpn *fpu_op(struct fpemu *fe);
115 1.1 briggs
116 1.1 briggs Where fe is a pointer to a struct fpemu in which frame, fpframe, and
117 1.1 briggs fetched operands are accessible. That's right, you don't have to
118 1.1 briggs fetch the operands by yourself in your emulation funtion. For
119 1.1 briggs instance, the parts calling FSQRT, FSUB, FADD and FTST look like:
120 1.1 briggs
121 1.1 briggs switch(word1 & 0x3F) {
122 1.1 briggs [...]
123 1.1 briggs case 0x04: /* fsqrt */
124 1.1 briggs res = fpu_sqrt(fe);
125 1.1 briggs break;
126 1.1 briggs [...]
127 1.1 briggs case 0x28: /* fsub */
128 1.1 briggs fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
129 1.1 briggs case 0x22: /* fadd */
130 1.1 briggs res = fpu_add(fe);
131 1.1 briggs break;
132 1.1 briggs [...]
133 1.1 briggs case 0x3A: /* ftst */
134 1.1 briggs res = &fe->fe_f2;
135 1.1 briggs no_store = 1;
136 1.1 briggs break;
137 1.1 briggs [...]
138 1.1 briggs default:
139 1.1 briggs sig = SIGILL;
140 1.1 briggs } /* switch */
141 1.1 briggs
142 1.1 briggs Here, fe->fe_f1 and fe->fe_f2 are fetched operands. You can use
143 1.1 briggs fe->fe_f3 for storing the result, or you can return a pointer to
144 1.1 briggs either operand if you want to. At any rate, you have to follow
145 1.1 briggs the following rules:
146 1.1 briggs
147 1.1 briggs 1) A dyadic instruction takes two operands fe->fe_f1 and fe->fe_f2.
148 1.1 briggs 2) A monadic instruction takes one operands fe->fe_f2 (NOT fe_f1).
149 1.1 briggs 3) Must return a pointer to struct fpn where the result is stored,
150 1.1 briggs and assign the pointer to the variable "res".
151 1.1 briggs 4) If exceptions are detected, set corresponding bits in fe->fe_fpsr.
152 1.1 briggs The rest is taken care of in fpu_emul_arith().
153 1.1 briggs 5) Condition code need not be calculated. It's taken care of in
154 1.1 briggs fpu_emul_arith().
155 1.1 briggs
156 1.4 briggs Actually, after above was written, stubs for the missing functions were
157 1.4 briggs added to the source, so you do not have to change fpu_emul_arith() at
158 1.4 briggs all. Function names and prototypes are in fpu_arith_proto.h, and all
159 1.4 briggs except fpu_sincos() follow the rules above. fpu_sincos() is declared
160 1.4 briggs as
161 1.4 briggs
162 1.4 briggs struct fpn *fpu_sincos(struct fpemu *fe, int cosreg);
163 1.4 briggs
164 1.4 briggs where cosreg is the FP register number to which cosine of the argument
165 1.4 briggs is calculated and assigned. Sine of the argument is stored into the
166 1.4 briggs destination register in the same manner as the other arithmetic
167 1.4 briggs functions.
168