Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
1da177e4 LT |
2 | #ifndef _ASM_MATH_EMU_H |
3 | #define _ASM_MATH_EMU_H | |
4 | ||
5 | #include <asm/setup.h> | |
6 | #include <linux/linkage.h> | |
7 | ||
8 | /* Status Register bits */ | |
9 | ||
10 | /* accrued exception bits */ | |
11 | #define FPSR_AEXC_INEX 3 | |
12 | #define FPSR_AEXC_DZ 4 | |
13 | #define FPSR_AEXC_UNFL 5 | |
14 | #define FPSR_AEXC_OVFL 6 | |
15 | #define FPSR_AEXC_IOP 7 | |
16 | ||
17 | /* exception status bits */ | |
18 | #define FPSR_EXC_INEX1 8 | |
19 | #define FPSR_EXC_INEX2 9 | |
20 | #define FPSR_EXC_DZ 10 | |
21 | #define FPSR_EXC_UNFL 11 | |
22 | #define FPSR_EXC_OVFL 12 | |
23 | #define FPSR_EXC_OPERR 13 | |
24 | #define FPSR_EXC_SNAN 14 | |
25 | #define FPSR_EXC_BSUN 15 | |
26 | ||
27 | /* quotient byte, assumes big-endian, of course */ | |
28 | #define FPSR_QUOTIENT(fpsr) (*((signed char *) &(fpsr) + 1)) | |
29 | ||
30 | /* condition code bits */ | |
31 | #define FPSR_CC_NAN 24 | |
32 | #define FPSR_CC_INF 25 | |
33 | #define FPSR_CC_Z 26 | |
34 | #define FPSR_CC_NEG 27 | |
35 | ||
36 | ||
37 | /* Control register bits */ | |
38 | ||
39 | /* rounding mode */ | |
40 | #define FPCR_ROUND_RN 0 /* round to nearest/even */ | |
41 | #define FPCR_ROUND_RZ 1 /* round to zero */ | |
42 | #define FPCR_ROUND_RM 2 /* minus infinity */ | |
43 | #define FPCR_ROUND_RP 3 /* plus infinity */ | |
44 | ||
45 | /* rounding precision */ | |
46 | #define FPCR_PRECISION_X 0 /* long double */ | |
47 | #define FPCR_PRECISION_S 1 /* double */ | |
48 | #define FPCR_PRECISION_D 2 /* float */ | |
49 | ||
50 | ||
51 | /* Flags to select the debugging output */ | |
52 | #define PDECODE 0 | |
53 | #define PEXECUTE 1 | |
54 | #define PCONV 2 | |
55 | #define PNORM 3 | |
56 | #define PREGISTER 4 | |
57 | #define PINSTR 5 | |
58 | #define PUNIMPL 6 | |
59 | #define PMOVEM 7 | |
60 | ||
61 | #define PMDECODE (1<<PDECODE) | |
62 | #define PMEXECUTE (1<<PEXECUTE) | |
63 | #define PMCONV (1<<PCONV) | |
64 | #define PMNORM (1<<PNORM) | |
65 | #define PMREGISTER (1<<PREGISTER) | |
66 | #define PMINSTR (1<<PINSTR) | |
67 | #define PMUNIMPL (1<<PUNIMPL) | |
68 | #define PMMOVEM (1<<PMOVEM) | |
69 | ||
70 | #ifndef __ASSEMBLY__ | |
71 | ||
72 | #include <linux/kernel.h> | |
73 | #include <linux/sched.h> | |
74 | ||
75 | union fp_mant64 { | |
76 | unsigned long long m64; | |
77 | unsigned long m32[2]; | |
78 | }; | |
79 | ||
80 | union fp_mant128 { | |
81 | unsigned long long m64[2]; | |
82 | unsigned long m32[4]; | |
83 | }; | |
84 | ||
85 | /* internal representation of extended fp numbers */ | |
86 | struct fp_ext { | |
87 | unsigned char lowmant; | |
88 | unsigned char sign; | |
89 | unsigned short exp; | |
90 | union fp_mant64 mant; | |
91 | }; | |
92 | ||
93 | /* C representation of FPU registers */ | |
94 | /* NOTE: if you change this, you have to change the assembler offsets | |
95 | below and the size in <asm/fpu.h>, too */ | |
96 | struct fp_data { | |
97 | struct fp_ext fpreg[8]; | |
98 | unsigned int fpcr; | |
99 | unsigned int fpsr; | |
100 | unsigned int fpiar; | |
101 | unsigned short prec; | |
102 | unsigned short rnd; | |
103 | struct fp_ext temp[2]; | |
104 | }; | |
105 | ||
106 | #if FPU_EMU_DEBUG | |
107 | extern unsigned int fp_debugprint; | |
108 | ||
109 | #define dprint(bit, fmt, args...) ({ \ | |
110 | if (fp_debugprint & (1 << (bit))) \ | |
111 | printk(fmt, ## args); \ | |
112 | }) | |
113 | #else | |
114 | #define dprint(bit, fmt, args...) | |
115 | #endif | |
116 | ||
117 | #define uprint(str) ({ \ | |
118 | static int __count = 3; \ | |
119 | \ | |
120 | if (__count > 0) { \ | |
121 | printk("You just hit an unimplemented " \ | |
122 | "fpu instruction (%s)\n", str); \ | |
123 | printk("Please report this to ....\n"); \ | |
124 | __count--; \ | |
125 | } \ | |
126 | }) | |
127 | ||
128 | #define FPDATA ((struct fp_data *)current->thread.fp) | |
129 | ||
130 | #else /* __ASSEMBLY__ */ | |
131 | ||
132 | #define FPDATA %a2 | |
133 | ||
134 | /* offsets from the base register to the floating point data in the task struct */ | |
135 | #define FPD_FPREG (TASK_THREAD+THREAD_FPREG+0) | |
136 | #define FPD_FPCR (TASK_THREAD+THREAD_FPREG+96) | |
137 | #define FPD_FPSR (TASK_THREAD+THREAD_FPREG+100) | |
138 | #define FPD_FPIAR (TASK_THREAD+THREAD_FPREG+104) | |
139 | #define FPD_PREC (TASK_THREAD+THREAD_FPREG+108) | |
140 | #define FPD_RND (TASK_THREAD+THREAD_FPREG+110) | |
141 | #define FPD_TEMPFP1 (TASK_THREAD+THREAD_FPREG+112) | |
142 | #define FPD_TEMPFP2 (TASK_THREAD+THREAD_FPREG+124) | |
143 | #define FPD_SIZEOF (TASK_THREAD+THREAD_FPREG+136) | |
144 | ||
145 | /* offsets on the stack to access saved registers, | |
146 | * these are only used during instruction decoding | |
147 | * where we always know how deep we're on the stack. | |
148 | */ | |
149 | #define FPS_DO (PT_D0) | |
150 | #define FPS_D1 (PT_D1) | |
151 | #define FPS_D2 (PT_D2) | |
152 | #define FPS_A0 (PT_A0) | |
153 | #define FPS_A1 (PT_A1) | |
154 | #define FPS_A2 (PT_A2) | |
155 | #define FPS_SR (PT_SR) | |
156 | #define FPS_PC (PT_PC) | |
157 | #define FPS_EA (PT_PC+6) | |
158 | #define FPS_PC2 (PT_PC+10) | |
159 | ||
160 | .macro fp_get_fp_reg | |
161 | lea (FPD_FPREG,FPDATA,%d0.w*4),%a0 | |
162 | lea (%a0,%d0.w*8),%a0 | |
163 | .endm | |
164 | ||
165 | /* Macros used to get/put the current program counter. | |
166 | * 020/030 use a different stack frame then 040/060, for the | |
167 | * 040/060 the return pc points already to the next location, | |
168 | * so this only needs to be modified for jump instructions. | |
169 | */ | |
170 | .macro fp_get_pc dest | |
171 | move.l (FPS_PC+4,%sp),\dest | |
172 | .endm | |
173 | ||
174 | .macro fp_put_pc src,jump=0 | |
175 | move.l \src,(FPS_PC+4,%sp) | |
176 | .endm | |
177 | ||
178 | .macro fp_get_instr_data f,s,dest,label | |
179 | getuser \f,%sp@(FPS_PC+4)@(0),\dest,\label,%sp@(FPS_PC+4) | |
180 | addq.l #\s,%sp@(FPS_PC+4) | |
181 | .endm | |
182 | ||
183 | .macro fp_get_instr_word dest,label,addr | |
184 | fp_get_instr_data w,2,\dest,\label,\addr | |
185 | .endm | |
186 | ||
187 | .macro fp_get_instr_long dest,label,addr | |
188 | fp_get_instr_data l,4,\dest,\label,\addr | |
189 | .endm | |
190 | ||
191 | /* These macros are used to read from/write to user space | |
192 | * on error we jump to the fixup section, load the fault | |
193 | * address into %a0 and jump to the exit. | |
194 | * (derived from <asm/uaccess.h>) | |
195 | */ | |
196 | .macro getuser size,src,dest,label,addr | |
197 | | printf ,"[\size<%08x]",1,\addr | |
198 | .Lu1\@: moves\size \src,\dest | |
199 | ||
200 | .section .fixup,"ax" | |
201 | .even | |
202 | .Lu2\@: move.l \addr,%a0 | |
203 | jra \label | |
204 | .previous | |
205 | ||
206 | .section __ex_table,"a" | |
207 | .align 4 | |
208 | .long .Lu1\@,.Lu2\@ | |
209 | .previous | |
210 | .endm | |
211 | ||
212 | .macro putuser size,src,dest,label,addr | |
213 | | printf ,"[\size>%08x]",1,\addr | |
214 | .Lu1\@: moves\size \src,\dest | |
215 | .Lu2\@: | |
216 | ||
217 | .section .fixup,"ax" | |
218 | .even | |
219 | .Lu3\@: move.l \addr,%a0 | |
220 | jra \label | |
221 | .previous | |
222 | ||
223 | .section __ex_table,"a" | |
224 | .align 4 | |
225 | .long .Lu1\@,.Lu3\@ | |
226 | .long .Lu2\@,.Lu3\@ | |
227 | .previous | |
228 | .endm | |
229 | ||
230 | ||
231 | .macro movestack nr,arg1,arg2,arg3,arg4,arg5 | |
232 | .if \nr | |
233 | movestack (\nr-1),\arg2,\arg3,\arg4,\arg5 | |
234 | move.l \arg1,-(%sp) | |
235 | .endif | |
236 | .endm | |
237 | ||
238 | .macro printf bit=-1,string,nr=0,arg1,arg2,arg3,arg4,arg5 | |
239 | #ifdef FPU_EMU_DEBUG | |
240 | .data | |
241 | .Lpdata\@: | |
242 | .string "\string" | |
243 | .previous | |
244 | ||
245 | movem.l %d0/%d1/%a0/%a1,-(%sp) | |
246 | .if \bit+1 | |
247 | #if 0 | |
248 | moveq #\bit,%d0 | |
249 | andw #7,%d0 | |
250 | btst %d0,fp_debugprint+((31-\bit)/8) | |
251 | #else | |
252 | btst #\bit,fp_debugprint+((31-\bit)/8) | |
253 | #endif | |
254 | jeq .Lpskip\@ | |
255 | .endif | |
256 | movestack \nr,\arg1,\arg2,\arg3,\arg4,\arg5 | |
257 | pea .Lpdata\@ | |
258 | jsr printk | |
259 | lea ((\nr+1)*4,%sp),%sp | |
260 | .Lpskip\@: | |
261 | movem.l (%sp)+,%d0/%d1/%a0/%a1 | |
262 | #endif | |
263 | .endm | |
264 | ||
265 | .macro printx bit,fp | |
266 | #ifdef FPU_EMU_DEBUG | |
267 | movem.l %d0/%a0,-(%sp) | |
268 | lea \fp,%a0 | |
269 | #if 0 | |
270 | moveq #'+',%d0 | |
271 | tst.w (%a0) | |
272 | jeq .Lx1\@ | |
273 | moveq #'-',%d0 | |
274 | .Lx1\@: printf \bit," %c",1,%d0 | |
275 | move.l (4,%a0),%d0 | |
276 | bclr #31,%d0 | |
277 | jne .Lx2\@ | |
278 | printf \bit,"0." | |
279 | jra .Lx3\@ | |
280 | .Lx2\@: printf \bit,"1." | |
281 | .Lx3\@: printf \bit,"%08x%08x",2,%d0,%a0@(8) | |
282 | move.w (2,%a0),%d0 | |
283 | ext.l %d0 | |
284 | printf \bit,"E%04x",1,%d0 | |
285 | #else | |
286 | printf \bit," %08x%08x%08x",3,%a0@,%a0@(4),%a0@(8) | |
287 | #endif | |
288 | movem.l (%sp)+,%d0/%a0 | |
289 | #endif | |
290 | .endm | |
291 | ||
292 | .macro debug instr,args | |
293 | #ifdef FPU_EMU_DEBUG | |
294 | \instr \args | |
295 | #endif | |
296 | .endm | |
297 | ||
298 | ||
299 | #endif /* __ASSEMBLY__ */ | |
300 | ||
301 | #endif /* _ASM_FRV_MATH_EMU_H */ | |
302 |