1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Inline functions (gcc style 386 asm).
12 *
13 * By Shawn Hargreaves.
14 *
15 * See readme.txt for copyright information.
16 */
17
18
19 #if (!defined ALLEGRO_GCC) || (!defined ALLEGRO_I386)
20 #error bad include
21 #endif
22
23 #ifdef ALLEGRO_IMPORT_GFX_ASM
24
25 /* _default_ds:
26 * Return a copy of the current %ds selector.
27 */
28 AL_INLINE(int, _default_ds, (void),
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
29 {
30 short result;
31
32 __asm__ (
33 " movw %%ds, %0 "
34
35 : "=r" (result)
36 );
37
38 return result;
39 })
40
41
42
43 /* bmp_write_line:
44 * Bank switch function.
45 */
46 AL_INLINE(uintptr_t, bmp_write_line, (BITMAP *bmp, int lyne),
47 {
48 uintptr_t result;
49
50 __asm__ volatile (
51 " call *%3 "
52
53 : "=a" (result) /* result in eax */
54
55 : "d" (bmp), /* bitmap in edx */
56 "0" (lyne), /* line number in eax */
57 "r" (bmp->write_bank) /* the bank switch routine */
58 );
59
60 return result;
61 })
62
63
64
65 /* bmp_read_line:
66 * Bank switch function.
67 */
68 AL_INLINE(uintptr_t, bmp_read_line, (BITMAP *bmp, int lyne),
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
69 {
70 uintptr_t result;
71
72 __asm__ volatile (
73 " call *%3 "
74
75 : "=a" (result) /* result in eax */
76
77 : "d" (bmp), /* bitmap in edx */
78 "0" (lyne), /* line number in eax */
79 "r" (bmp->read_bank) /* the bank switch routine */
80 );
81
82 return result;
83 })
84
85
86
87 /* bmp_unwrite_line:
88 * Terminate bank switch function.
89 */
90 AL_INLINE(void, bmp_unwrite_line, (BITMAP *bmp),
91 {
92 __asm__ volatile (
93 " call *%1 "
94 :
95 : "d" (bmp), /* bitmap in edx */
96 "r" (bmp->vtable->unwrite_bank) /* the bank switch routine */
97 );
98 })
99
100 #endif /* ALLEGRO_IMPORT_GFX_ASM */
101
102
103 #ifdef ALLEGRO_IMPORT_MATH_ASM
104
105 /* Helper macro that makes the compiler reduce al_fixadd(), al_fixsub(), al_fixmul() and
106 al_fixdiv() calls to a single constant if both operands are constant. Since
107 this doesn't work unless we compile with optimization, it's better to skip
108 the test then. */
109 #if (defined __OPTIMIZE__) && ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)))
110 #define __PRECALCULATE_CONSTANTS(calc) \
111 if(__builtin_constant_p(x) && __builtin_constant_p(y)) { \
112 if((calc) > (double)0x7FFFFFFF) { \
113 al_set_errno(ERANGE); \
114 return 0x7FFFFFFF; \
115 } \
116 else if(-(calc) > (double)0x7FFFFFFF) { \
117 al_set_errno(ERANGE); \
118 return -0x7FFFFFFF; \
119 } \
120 else \
121 return (al_fixed)(calc); \
122 } \
123 else
124 #else
125 #define __PRECALCULATE_CONSTANTS(calc)
126 #endif
127
128
129
130 /* al_fixadd:
131 * Fixed point (16.16) addition.
132 */
133 AL_INLINE(al_fixed, al_fixadd, (al_fixed x, al_fixed y),
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
134 {
135 al_fixed result;
136 int errnum = 0;
137
138 __PRECALCULATE_CONSTANTS(x + (double)y)
139 {
140 __asm__ (
141 " addl %2, %0 ; " /* do the addition */
142 " jno 0f ; " /* check for overflow */
143
144 " movl %4, %0 ; " /* on overflow, set errno */
145 " movl %3, (%0) ; "
146 " movl $0x7FFFFFFF, %0 ; " /* and return MAXINT */
147 " cmpl $0, %2 ; "
148 " jg 0f ; "
149 " negl %0 ; "
150
151 " 0: " /* finished */
152
153 : "=r" (result) /* result in a register */
154
155 : "0" (x), /* x in the output register */
156 "rm" (y), /* y can go in register or memory */
157 "i" (ERANGE),
158 "m" (errnum)
159
160 : "%cc", "memory" /* clobbers flags and errno */
161 );
162
163 if (errnum)
164 al_set_errno(errnum);
165
166 return result;
167 }
168 })
169
170
171
172 /* al_fixsub:
173 * Fixed point (16.16) subtraction.
174 */
175 AL_INLINE(al_fixed, al_fixsub, (al_fixed x, al_fixed y),
176 {
177 al_fixed result;
178 int errnum = 0;
179
180 __PRECALCULATE_CONSTANTS(x - (double)y)
181 {
182 __asm__ (
183 " subl %2, %0 ; " /* do the subtraction */
184 " jno 0f ; " /* check for overflow */
185
186 " movl %4, %0 ; " /* on overflow, set errno */
187 " movl %3, (%0) ; "
188 " movl $0x7FFFFFFF, %0 ; " /* and return MAXINT */
189 " cmpl $0, %2 ; "
190 " jl 0f ; "
191 " negl %0 ; "
192
193 " 0: " /* finished */
194
195 : "=r" (result) /* result in a register */
196
197 : "0" (x), /* x in the output register */
198 "rm" (y), /* y can go in register or memory */
199 "i" (ERANGE),
200 "m" (errnum)
201
202 : "%cc", "memory" /* clobbers flags and errno */
203 );
204
205 if (errnum)
206 al_set_errno(errnum);
207
208 return result;
209 }
210 })
211
212
213
214 /* al_fixmul:
215 * Fixed point (16.16) multiplication.
216 */
217 AL_INLINE(al_fixed, al_fixmul, (al_fixed x, al_fixed y),
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
218 {
219 al_fixed edx __attribute__ ((__unused__));
220 al_fixed result;
221 int errnum = 0;
222
223 __PRECALCULATE_CONSTANTS(x / 65536.0 * y)
224 {
225 __asm__ (
226 " movl %2, %%eax ; "
227 " imull %3 ; " /* do the multiply */
228 " shrdl $16, %%edx, %%eax ; "
229
230 " sarl $15, %%edx ; " /* check for overflow */
231 " jz 0f ; "
232 " cmpl $-1, %%edx ; "
233 " je 0f ; "
234
235 " movl %5, %%eax ; " /* on overflow, set errno */
236 " movl %4, (%%eax) ; "
237 " movl $0x7FFFFFFF, %%eax ; " /* and return MAXINT */
238 " cmpl $0, %2 ; "
239 " jge 1f ; "
240 " negl %%eax ; "
241 " 1: "
242 " cmpl $0, %3 ; "
243 " jge 0f ; "
244 " negl %%eax ; "
245
246 " .balign 4, 0x90 ; "
247
248 " 0: " /* finished */
249
250 : "=&a" (result), /* the result has to go in eax */
251 "=&d" (edx) /* reliably reserve edx */
252
253 : "mr" (x), /* x and y can be regs or mem */
254 "mr" (y),
255 "i" (ERANGE),
256 "m" (errnum)
257
258 : "%cc", "memory" /* clobbers flags and errno */
259 );
260
261 if (errnum)
262 al_set_errno(errnum);
263
264 return result;
265 }
266 })
267
268
269
270 /* al_fixdiv:
271 * Fixed point (16.16) division.
272 */
273 AL_INLINE(al_fixed, al_fixdiv, (al_fixed x, al_fixed y),
274 {
275 al_fixed edx __attribute__ ((__unused__));
276 al_fixed reg __attribute__ ((__unused__));
277 al_fixed result;
278 int errnum = 0;
279
280 __PRECALCULATE_CONSTANTS(x * 65536.0 / y)
281 {
282 __asm__ (
283 " testl %%eax, %%eax ; " /* test sign of x */
284 " js 3f ; "
285
286 " testl %2, %2 ; " /* test sign of y */
287 " jns 4f ; "
288 " negl %2 ; "
289
290 " 0: " /* result will be negative */
291 " movl %%eax, %%edx ; " /* check the range is ok */
292 " shrl $16, %%edx ; "
293 " shll $16, %%eax ; "
294 " cmpl %2, %%edx ; "
295 " jae 1f ; "
296
297 " divl %2 ; " /* do the divide */
298 " testl %%eax, %%eax ; "
299 " jns 2f ; "
300
301 " 1: "
302 " movl %6, %%eax ; " /* on overflow, set errno */
303 " movl %5, (%%eax) ; "
304 " movl $0x7FFFFFFF, %%eax ; " /* and return MAXINT */
305
306 " 2: "
307 " negl %%eax ; " /* fix up the sign of the result */
308 " jmp 6f ; "
309
310 " .balign 4, 0x90 ; "
311
312 " 3: " /* x is negative */
313 " negl %%eax ; "
314 " testl %2, %2 ; " /* test sign of y */
315 " jns 0b ; "
316 " negl %2 ; "
317
318 " 4: " /* result will be positive */
319 " movl %%eax, %%edx ; " /* check the range is ok */
320 " shrl $16, %%edx ; "
321 " shll $16, %%eax ; "
322 " cmpl %2, %%edx ; "
323 " jae 5f ; "
324
325 " divl %2 ; " /* do the divide */
326 " testl %%eax, %%eax ; "
327 " jns 6f ; "
328
329 " 5: "
330 " movl %6, %%eax ; " /* on overflow, set errno */
331 " movl %5, (%%eax) ; "
332 " movl $0x7FFFFFFF, %%eax ; " /* and return MAXINT */
333
334 " 6: " /* finished */
335
336 : "=a" (result), /* the result has to go in eax */
337 "=&d" (edx), /* reliably reserve edx */
338 "=r" (reg) /* input operand will be clobbered */
339
340 : "0" (x), /* x in eax */
341 "2" (y), /* y in register */
342 "i" (ERANGE),
343 "m" (errnum)
344
345 : "%cc", "memory" /* clobbers flags and memory */
346 );
347
348 if (errnum)
349 al_set_errno(errnum);
350
351 return result;
352 }
353 })
354
355
356
357 /* al_fixfloor:
358 * Fixed point version of floor().
359 * Note that it returns an integer result (not a fixed one)
360 */
361 AL_INLINE(int, al_fixfloor, (al_fixed x),
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
362 {
363 int result;
364
365 __asm__ (
366 " sarl $16, %0 " /* convert to int */
367
368 : "=r" (result) /* result in a register */
369
370 : "0" (x) /* x in the output register */
371 );
372
373 return result;
374 })
375
376
377
378 /* al_fixceil:
379 * Fixed point version of ceil().
380 * Note that it returns an integer result (not a fixed one)
381 */
382 AL_INLINE(int, al_fixceil, (al_fixed x),
383 {
384 int result;
385 int errnum = 0;
386
387 __asm__ (
388 " addl $0xFFFF, %0 ;" /* ceil () */
389 " jns 0f ;"
390 " jo 1f ;"
391
392 "0:"
393 " sarl $16, %0 ;" /* convert to int */
394 " jmp 2f ;"
395
396 "1:"
397 " movl %3, %0 ;" /* on overflow, set errno */
398 " movl %2, (%0) ;"
399 " movl $0x7FFF, %0 ;" /* and return large int */
400
401 "2:"
402 : "=r" (result) /* result in a register */
403
404 : "0" (x), /* x in the output register */
405 "i" (ERANGE),
406 "m" (errnum)
407
408 : "%cc", "memory" /* clobbers flags and errno */
409 );
410
411 if (errnum)
412 al_set_errno(errnum);
413
414 return result;
415 })
416
417
418
419 #undef __PRECALCULATE_CONSTANTS
420
421 #endif /* ALLEGRO_IMPORT_MATH_ASM */
422