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