/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Inline functions (Watcom style 386 asm).
 *
 *      By Shawn Hargreaves.
 *
 *      See readme.txt for copyright information.
 */


#if (!defined ALLEGRO_WATCOM) || (!defined ALLEGRO_I386)
   #error bad include
#endif


#ifdef ALLEGRO_IMPORT_GFX_ASM

/* _default_ds:
 *  Return a copy of the current %ds selector.
 */
int _default_ds(void);

#pragma aux _default_ds =     \
   " mov eax, 0 "             \
   " mov ax, ds "             \
			      \
   value [eax];



/* _my_cs:
 *  Return a copy of the current %cs selector.
 */
int _my_cs(void);

#pragma aux _my_cs =          \
   " mov eax, 0 "             \
   " mov ax, cs "             \
			      \
   value [eax];



/* bmp_write_line/bmp_read_line:
 *  Bank switch functions.
 */
uintptr_t _bmp_bank_switcher(BITMAP *bmp, int lyne, void *bank_switch);

#pragma aux _bmp_bank_switcher =    \
   " call ecx "                     \
				    \
   parm [edx] [eax] [ecx]           \
   value [eax];

#define bmp_write_line(bmp, lyne)   _bmp_bank_switcher(bmp, lyne, (void *)bmp->write_bank)
#define bmp_read_line(bmp, lyne)    _bmp_bank_switcher(bmp, lyne, (void *)bmp->read_bank)



/* bmp_unwrite_line:
 *  Terminate bank switch function.
 */
void _bmp_unbank_switcher(BITMAP *bmp, void *bank_unswitcher);

#pragma aux _bmp_unbank_switcher =  \
   " call ecx "                     \
				    \
   parm [edx] [ecx];

#define bmp_unwrite_line(bmp)       _bmp_unbank_switcher(bmp, (void *)bmp->vtable->unwrite_bank)

#endif /* ALLEGRO_IMPORT_GFX_ASM */


#ifdef ALLEGRO_IMPORT_MATH_ASM

/* _set_errno_erange:
 *  Watcom's asm syntax doesn't provide any nice way to do this inline...
 */
AL_INLINE(void, _set_errno_erange, (void),
{
   al_set_errno(ERANGE);
})



/* fixadd:
 *  Fixed point (16.16) addition.
 */
fixed fixadd(fixed x, fixed y);

#pragma aux fixadd =             \
   "  add eax, edx "             \
   "  jno Out1 "                 \
   "  call _set_errno_erange "   \
   "  mov eax, 0x7FFFFFFF "      \
   "  cmp edx, 0 "               \
   "  jg Out1 "                  \
   "  neg eax "                  \
   " Out1: "                     \
				 \
   parm [eax] [edx]              \
   value [eax];



/* fixsub:
 *  Fixed point (16.16) subtraction.
 */
fixed fixsub(fixed x, fixed y);

#pragma aux fixsub =             \
   "  sub eax, edx "             \
   "  jno Out1 "                 \
   "  call _set_errno_erange "   \
   "  mov eax, 0x7FFFFFFF "      \
   "  cmp edx, 0 "               \
   "  jl Out1 "                  \
   "  neg eax "                  \
   " Out1: "                     \
				 \
   parm [eax] [edx]              \
   value [eax];



/* fixmul:
 *  Fixed point (16.16) multiplication.
 */
fixed fixmul(fixed x, fixed y);

#pragma aux fixmul =             \
   "  mov eax, ebx "             \
   "  imul ecx "                 \
   "  shrd eax, edx, 16 "        \
   "  sar edx, 15 "              \
   "  jz Out2 "                  \
   "  cmp edx, -1 "              \
   "  jz Out2 "                  \
   "  call _set_errno_erange "   \
   "  mov eax, 0x7FFFFFFF "      \
   "  cmp ebx, 0 "               \
   "  jge Out1 "                 \
   "  neg eax "                  \
   " Out1: "                     \
   "  cmp ecx, 0 "               \
   "  jge Out2 "                 \
   "  neg eax "                  \
   " Out2: "                     \
				 \
   parm [ebx] [ecx]              \
   modify [edx]                  \
   value [eax];



/* fixdiv:
 *  Fixed point (16.16) division.
 */
fixed fixdiv(fixed x, fixed y);

#pragma aux fixdiv =             \
   "  xor ebx, ebx "             \
   "  or eax, eax "              \
   "  jns Out1 "                 \
   "  neg eax "                  \
   "  inc ebx "                  \
   " Out1: "                     \
   "  or ecx, ecx "              \
   "  jns Out2 "                 \
   "  neg ecx "                  \
   "  inc ebx "                  \
   " Out2: "                     \
   "  mov edx, eax "             \
   "  shr edx, 0x10 "            \
   "  shl eax, 0x10 "            \
   "  cmp edx, ecx "             \
   "  jae Out3 "                 \
   "  div ecx "                  \
   "  or eax, eax "              \
   "  jns Out4 "                 \
   " Out3: "                     \
   "  call _set_errno_erange "   \
   "  mov eax, 0x7FFFFFFF "      \
   " Out4: "                     \
   "  test ebx, 1 "              \
   "  je Out5 "                  \
   "  neg eax "                  \
   " Out5: "                     \
				 \
   parm [eax] [ecx]              \
   modify [ebx edx]              \
   value [eax];



/* fixfloor :
 * Fixed point version of floor().
 * Note that it returns an integer result (not a fixed one)
 */
int fixfloor(fixed x);

#pragma aux fixfloor =           \
   "  sar eax, 0x10 "		 \
				 \
   parm [eax]			 \
   value [eax];



/* fixceil :
 * Fixed point version of ceil().
 * Note that it returns an integer result (not a fixed one)
 */
int fixceil(fixed x);

#pragma aux fixceil =            \
   "  add eax, 0xFFFF "		 \
   "  jns Out1 "		 \
   "  jo  Out2 "		 \
   " Out1: "			 \
   "  sar eax, 0x10 "		 \
   "  jmp Out3 "		 \
   " Out2: "			 \
   "  call _set_errno_erange "	 \
   "  mov eax, 0x7FFF "		 \
   " Out3: "			 \
				 \
   parm [eax]			 \
   value [eax];

#endif /* ALLEGRO_IMPORT_MATH_ASM */

