// Function-wrapped Watcom pragmas
// by Jonathon Fowler (jf@jonof.id.au)
//
// These functions represent some of the more longer-winded pragmas
// from the original pragmas.h wrapped into functions for easier
// use since many jumps and whatnot make it harder to write macro-
// inline versions. I'll eventually convert these to macro-inline
// equivalents.		--Jonathon

//#include "pragmas.h"
#include "compat.h"

long dmval;

#if defined(__GNUC__) && defined(__i386__) && !defined(NOASM)	// NOASM

//
// GCC Inline Assembler version
//

#define ASM __asm__ __volatile__


long boundmulscale(long a, long b, long c)
{
	ASM (
		"imull %%ebx\n\t"
		"movl %%edx, %%ebx\n\t"		// mov ebx, edx
		"shrdl %%cl, %%edx, %%eax\n\t"	// mov eax, edx, cl
		"sarl %%cl, %%edx\n\t"		// sar edx, cl
		"xorl %%eax, %%edx\n\t"		// xor edx, eax
		"js 0f\n\t"			// js checkit
		"xorl %%eax, %%edx\n\t"		// xor edx, eax
		"jz 1f\n\t"			// js skipboundit
		"cmpl $0xffffffff, %%edx\n\t"	// cmp edx, 0xffffffff
		"je 1f\n\t"			// je skipboundit
		"0:\n\t"			// checkit:
		"movl %%ebx, %%eax\n\t"		// mov eax, ebx
		"sarl $31, %%eax\n\t"		// sar eax, 31
		"xorl $0x7fffffff, %%eax\n\t"	// xor eax, 0x7fffffff
		"1:"				// skipboundit:
		: "+a" (a), "+b" (b), "+c" (c)	// input eax ebx ecx
		:
		: "edx", "cc"
	);
	return a;
}


void clearbufbyte(void *D, long c, long a)
{
	ASM (
		"cmpl $4, %%ecx\n\t"
		"jae 1f\n\t"
		"testb $1, %%cl\n\t"
		"jz 0f\n\t"			// jz preskip
		"stosb\n\t"
		"0:\n\t"			// preskip:
		"shrl $1, %%ecx\n\t"
		"rep\n\t"
		"stosw\n\t"
		"jmp 5f\n\t"			// jmp endit
		"1:\n\t"			// intcopy:
		"testl $1, %%edi\n\t"
		"jz 2f\n\t"			// jz skip1
		"stosb\n\t"
		"decl %%ecx\n\t"
		"2:\n\t"			// skip1:
		"testl $2, %%edi\n\t"
		"jz 3f\n\t"			// jz skip2
		"stosw\n\t"
		"subl $2, %%ecx\n\t"
		"3:\n\t"			// skip2:
		"movl %%ecx, %%ebx\n\t"
		"shrl $2, %%ecx\n\t"
		"rep\n\t"
		"stosl\n\t"
		"testb $2, %%bl\n\t"
		"jz 4f\n\t"			// jz skip3
		"stosw\n\t"
		"4:\n\t"			// skip3:
		"testb $1, %%bl\n\t"
		"jz 5f\n\t"			// jz endit
		"stosb\n\t"
		"5:"				// endit
		: "+D" (D), "+c" (c), "+a" (a) :
		: "ebx", "memory", "cc"
	);
}

void copybufbyte(void *S, void *D, long c)
{
	ASM (
		"cmpl $4, %%ecx\n\t"		// cmp ecx, 4
		"jae 1f\n\t"
		"testb $1, %%cl\n\t"		// test cl, 1
		"jz 0f\n\t"
		"movsb\n\t"
		"0:\n\t"			// preskip:
		"shrl $1, %%ecx\n\t"		// shr ecx, 1
		"rep\n\t"
		"movsw\n\t"
		"jmp 5f\n\t"
		"1:\n\t"			// intcopy:
		"testl $1, %%edi\n\t"		// test edi, 1
		"jz 2f\n\t"
		"movsb\n\t"
		"decl %%ecx\n\t"
		"2:\n\t"			// skip1:
		"testl $2, %%edi\n\t"		// test edi, 2
		"jz 3f\n\t"
		"movsw\n\t"
		"subl $2, %%ecx\n\t"		// sub ecx, 2
		"3:\n\t"			// skip2:
		"movl %%ecx, %%ebx\n\t"		// mov ebx, ecx
		"shrl $2, %%ecx\n\t"		// shr ecx ,2
		"rep\n\t"
		"movsl\n\t"
		"testb $2, %%bl\n\t"		// test bl, 2
		"jz 4f\n\t"
		"movsw\n\t"
		"4:\n\t"			// skip3:
		"testb $1, %%bl\n\t"		// test bl, 1
		"jz 5f\n\t"
		"movsb\n\t"
		"5:"				// endit:
		: "+c" (c), "+S" (S), "+D" (D) :
		: "ebx", "memory", "cc"
	);
}

void copybufreverse(void *S, void *D, long c)
{
	ASM (
		"shrl $1, %%ecx\n\t"
		"jnc 0f\n\t"		// jnc skipit1
		"movb (%%esi), %%al\n\t"
		"decl %%esi\n\t"
		"movb %%al, (%%edi)\n\t"
		"incl %%edi\n\t"
		"0:\n\t"		// skipit1:
		"shrl $1, %%ecx\n\t"
		"jnc 1f\n\t"		// jnc skipit2
		"movw -1(%%esi), %%ax\n\t"
		"subl $2, %%esi\n\t"
		"rorw $8, %%ax\n\t"
		"movw %%ax, (%%edi)\n\t"
		"addl $2, %%edi\n\t"
		"1:\n\t"		// skipit2
		"testl %%ecx, %%ecx\n\t"
		"jz 3f\n\t"		// jz endloop
		"2:\n\t"		// begloop
		"movl -3(%%esi), %%eax\n\t"
		"subl $4, %%esi\n\t"
		"bswapl %%eax\n\t"
		"movl %%eax, (%%edi)\n\t"
		"addl $4, %%edi\n\t"
		"decl %%ecx\n\t"
		"jnz 2b\n\t"		// jnz begloop
		"3:"
		: "+S" (S), "+D" (D), "+c" (c) :
		: "eax", "memory", "cc"
	);
}

#elif defined(__WATCOMC__) && !defined(NOASM)	// __GNUC__ && __i386__

//
// Watcom C Inline Assembler version
//

#elif defined(_MSC_VER) && !defined(NOASM)		// __WATCOMC__

//
// Microsoft C Inline Assembler version
//

#else				// _MSC_VER

//
// Generic C version
//

void qinterpolatedown16(long bufptr, long num, long val, long add)
{ // gee, I wonder who could have provided this...
    long i, *lptr = (long *)bufptr;
    for(i=0;i<num;i++) { lptr[i] = (val>>16); val += add; }
}

void qinterpolatedown16short(long bufptr, long num, long val, long add)
{ // ...maybe the same person who provided this too?
    long i; short *sptr = (short *)bufptr;
    for(i=0;i<num;i++) { sptr[i] = (short)(val>>16); val += add; }
}

void clearbuf(void *d, long c, long a)
{
	long *p = (long*)d;
	while ((c--) > 0) *(p++) = a;
}

void copybuf(void *s, void *d, long c)
{
	long *p = (long*)s, *q = (long*)d;
	while ((c--) > 0) *(q++) = *(p++);
}

void swapbuf4(void *a, void *b, long c)
{
	long *p = (long*)a, *q = (long*)b;
	long x, y;
	while ((c--) > 0) {
		x = *q;
		y = *p;
		*(q++) = y;
		*(p++) = x;
	}
}

void clearbufbyte(void *D, long c, long a)
{ // Cringe City
	char *p = (char*)D;
	long m[4] = { 0xffl,0xff00l,0xff0000l,0xff000000l };
	long n[4] = { 0,8,16,24 };
	long z=0;
	while ((c--) > 0) {
		*(p++) = (char)((a & m[z])>>n[z]);
		z=(z+1)&3;
	}
}

void copybufbyte(void *S, void *D, long c)
{
	char *p = (char*)S, *q = (char*)D;
	while((c--) > 0) *(q++) = *(p++);
}

void copybufreverse(void *S, void *D, long c)
{
	char *p = (char*)S, *q = (char*)D;
	while((c--) > 0) *(q++) = *(p--);
}

#endif


