/*
 *  inline.h 
 *
 *  Copyright by QNX Software Systems Limited 1990-1997. All rights reserved.
 */

#ifndef __INLINE_H_INCLUDED
#define __INLINE_H_INCLUDED

/*
    some handy pragma's for low-level work: 
*/

#ifndef __TYPES_H_INCLUDED
#include <sys/types.h>
#endif

#ifndef _I86_H_INCLUDED
#include <i86.h>
#endif

#ifdef __386__
    #define FAR
#else
	#define FAR __far
#endif

#ifdef __cplusplus
extern "C" {
#endif

	/* issues an int f3h which puts you in to the low level debugger. */
void    ll_debug(void);

	/* issues an int 3 to put you in the process debugger */
void	breakpoint(void);

	/* delays approximately 8 clocks * count */
void    delay_8X(unsigned count);

	/* returns the current value of the flags register */
unsigned    pswget(void);

	/* restores psw into flags register */
void    restore(unsigned psw);

	/* disables interrupts, returns previous value of flags */
unsigned    disable(void);

	/* enables interrupts, returns previous value of flags */
unsigned    enable(void);

	/* sets direction flag to forward, returns previous value of flags */
unsigned    str_forward(void);

	/* sets direction flag to reverse, returns previous value of flags */
unsigned    str_reverse(void);

	/* return the size of the segment */
unsigned segsize(ushort_t sel);

	/* verify a pointer/length is readable */
#define verr(p,len) \
    (_verr(FP_SEG(p)) ? segsize(FP_SEG(p)) >= (FP_OFF(p) + len) : 0)
uchar_t _verr(ushort_t seg);
    
	/* verify a pointer/length is writeable */
#define verw(p,len) \
    (_verw(FP_SEG(p)) ? segsize(FP_SEG(p)) >= (FP_OFF(p) + len) : 0)
uchar_t _verw(int seg);

   	/* return the current value of the 'cs' register */
ushort_t    _cs(void);
    
   	/* return the current value of the 'ds' register */
ushort_t    _ds(void);
    
   	/* return the current value of the 'es' register */
ushort_t    _es(void);
    
   	/* return the current value of the 'fs' register */
ushort_t    _fs(void);
    
   	/* return the current value of the 'gs' register */
ushort_t    _gs(void);
    
   	/* return the current value of the 'ss' register */
ushort_t    _ss(void);

	/* load segment registers register */
void ldds(unsigned __ds);
void ldes(unsigned __es);
void ldfs(unsigned __fs);
void ldgs(unsigned __gs);

	/* load stack pointer */
void ldesp(unsigned __esp);

	/* does 2 "jmp ." to avoid trashing IO device */
void    io_safe(void);

	/* input a byte from a port */
uchar_t  inb(ushort_t port);

	/* input a word from a port */
ushort_t  inw(ushort_t port);

	/* input a long from a port */
ulong_t  inl(ushort_t port);

	/* input a byte string from a port */
void	insb(void FAR *buff, unsigned len, ushort_t port );

	/* input a word string from a port */
void	insw(void FAR *buff, unsigned len, ushort_t port );

	/* input a long string from a port */
void	insl(void FAR *buff, unsigned len, ushort_t port );

	/* output a byte to a port */
void	outb(ushort_t port, uchar_t val );

	/* output a word to a port */
void	outw(ushort_t port, ushort_t val );

	/* output a long to a port */
void	outl(ushort_t port, ulong_t val );

	/* output a byte string to a port */
void	outsb(const void FAR *buff, unsigned len, ushort_t port );

	/* output a word string to a port */
void	outsw(const void FAR *buff, unsigned len, ushort_t port );

	/* output a long string to a port */
void	outsl(const void FAR *buff, unsigned len, ushort_t port );

	/* swaps byte ordering of a word */
ushort_t    swapw(ushort_t val);

	/* swaps byte ordering of a long */
ulong_t   swapl(ulong_t lval);

	/*
    	memcopies by 8,16 and 32 bits resp.
    	note nbytes is BYTES and is expected to be an even
        multiple of the copy size (ie 16 or 32).
	*/
memcpy8(void far *dst, const void far *src, unsigned nbytes);
memcpy16(void far *dst, const void far *src, unsigned nbytes);
memcpy32(void far *dst, const void far *src, unsigned nbytes);

	/* Read the Pentium's real time counter */
void rdtsc(void *ptr);

	/* Various floating point thingies */
void fninit(void);
int fsw(void);
int fnclex(void);
void fsave(void *addr);
void fnsave(void *addr);
void frstor(void *addr);

	/* Find high order on bit */
int bsr(long unsigned eax);

	/* Find high order on bit, handling case where nothing's on */
int bsr0(long unsigned eax);

	/* SMP Atomic compare and exchange operation */
int smp_cmpxchg(unsigned *dst, int cmp, int new);

	/* SMP Atomic or'ing of memory */
unsigned smp_locked_or(unsigned *addr, unsigned value);

	/* SMP Atomic anding'ing of memory */
unsigned smp_locked_and(unsigned *addr, unsigned value);

#ifdef __cplusplus
};
#endif

#pragma aux ll_debug   = "int 0xf3" parm nomemory [] modify nomemory exact []
#pragma aux breakpoint = "int 0x03" parm nomemory [] modify nomemory exact []

#pragma aux _verr = ".286p" \
					"verr ax" \
					"lahf" \
					"shr ax,14" \
					"and al,1" \
					parm [ax] value [al]

#pragma aux _verw = ".286p" \
					"verw ax" \
					"lahf" \
					"shr ax,14" \
					"and al,1" \
					parm [ax] value [al]

#pragma aux _cs = "mov ax,cs" parm nomemory [] modify nomemory exact [ax] value [ax]
#pragma aux _ds = "mov ax,ds" parm nomemory [] modify nomemory exact [ax] value [ax]
#pragma aux _es = "mov ax,es" parm nomemory [] modify nomemory exact [ax] value [ax]
#pragma aux _ss = "mov ax,ss" parm nomemory [] modify nomemory exact [ax] value [ax]

#pragma aux io_safe = 0xeb 0x00 0xeb 0x00 parm nomemory [] modify nomemory exact []

#pragma aux inb = "in al,dx" parm nomemory [dx] modify nomemory exact [al] value [al]
#pragma aux inw = "in ax,dx" parm nomemory [dx] modify nomemory exact [ax] value [ax]

#pragma aux outb = "out dx,al" parm nomemory [dx] [al] modify nomemory exact []
#pragma aux outw = "out dx,ax" parm nomemory [dx] [ax] modify nomemory exact []

#pragma aux swapw = "xchg al,ah" parm nomemory [ax] modify nomemory exact [ax] value [ax]

#pragma aux fninit = ".8087" "fninit" parm nomemory [ ] modify exact nomemory [ ]
#pragma aux fnclex = ".8087" "fnclex" modify exact nomemory [ ];

#ifdef __386__

#pragma aux _fs = ".386" "mov ax,fs" parm nomemory [] modify nomemory exact [ax] value [ax]
#pragma aux _gs = ".386" "mov ax,gs" parm nomemory [] modify nomemory exact [ax] value [ax]

#pragma aux ldds = \
			"mov ds,ax" \
			parm nomemory [ eax ] \
			modify exact nomemory [ ];

#pragma aux ldes = \
			"mov es,ax" \
			parm nomemory [ eax ] \
			modify exact nomemory [ ];

#pragma aux ldfs = \
			"mov fs,ax" \
			parm nomemory [ eax ] \
			modify exact nomemory [ ];

#pragma aux ldgs = \
			"mov gs,ax" \
			parm nomemory [ eax ] \
			modify exact nomemory [ ];

#pragma aux ldesp = \
			"mov esp,eax" \
			parm nomemory [ eax ] \
			modify exact nomemory [ ];

#pragma aux inl = ".386" "in eax,dx" parm nomemory [dx] modify nomemory exact [eax] value [eax]

#pragma aux outl = ".386" "out dx,eax" parm nomemory [dx] [eax] modify nomemory exact []

#pragma aux insb = "rep insb"\
    parm [edi] [ecx] [dx] \
    modify exact [ecx edi]

#pragma aux insw = "rep insw"\
    parm [edi] [ecx] [dx] \
    modify exact [ecx edi]

#pragma aux insl = ".386" "rep insd"\
    parm [edi] [ecx] [dx] \
    modify exact [ecx edi]

#pragma aux outsb = "rep outsb"\
    parm [esi] [ecx] [dx] \
    modify nomemory exact [ecx edi]

#pragma aux outsw = "rep outsw"\
    parm [esi] [ecx] [dx] \
    modify nomemory exact [ecx esi]

#pragma aux outsl = ".386" "rep outsd"\
    parm [esi] [ecx] [dx] \
    modify nomemory exact [ecx esi]

#pragma aux delay_8X = "here: loop here" parm nomemory [ecx] modify nomemory exact [ecx];

#pragma aux pswget = ".386" "pushfd" "pop eax" parm nomemory [] modify nomemory [] value  [eax];
#pragma aux restore = ".386" "popfd" parm routine nomemory [] modify nomemory exact [];
#pragma aux disable = ".386" "pushfd" "pop eax" "cli" parm nomemory [] modify exact [eax] value [eax]
#pragma aux enable = ".386" "pushfd" "sti" "pop eax" parm nomemory [] modify exact [eax] value [eax]
#pragma aux str_forward = ".386" "pushfd" "cld" "pop eax" parm nomemory [] modify exact [eax] value [eax]
#pragma aux str_reverse = ".386" "pushfd" "std" "pop eax" parm nomemory [] modify exact [eax] value [eax]

#pragma aux segsize = ".386p" "lsl eax,ax" parm nomemory [ax] modify exact nomemory [eax] value [eax]
            
#pragma aux swapl = ".386" "xchg al,ah" "ror eax,16" "xchg al,ah" parm nomemory [eax] modify nomemory [] value [eax]

#pragma aux rdtsc = \
			"db 0fh,31h" \
			"mov 0[ebx],eax" \
			"mov 4[ebx],edx" \
			parm nomemory [ebx] modify exact [eax edx];

#pragma aux fsw = \
			"xor eax,eax" \
			0xdf 0xe0						 /* fnstsw ax */ \
			modify exact nomemory [ eax ];

#pragma aux fsave = \
			".8087" \
			"fsave [eax]" \
			parm nomemory [ eax ] \
			modify exact [ ];

#pragma aux fnsave = \
			".8087" \
			"fnsave [eax]" \
			parm nomemory [ eax ] \
			modify exact [ ];

#pragma aux frstor = \
			".8087" \
			"frstor [eax]" \
			parm [ eax ] \
			modify exact nomemory [ ];

#pragma aux bsr =\
			"bsr eax,eax"\
			parm nomemory [ eax ]\
			modify exact nomemory [ eax ];

#pragma aux bsr0 =\
			"bsr eax,eax"\
			"jnz l1"\
			"xor eax,eax"\
			"l1:"\
			parm nomemory [ eax ]\
			modify exact nomemory [ eax ];

	/* The NOP's are to work around an NS486 bug with LOCK prefixes */
#pragma aux smp_cmpxchg = \
			".486" \
			"nop" \
			"nop" \
			"nop" \
			"lock cmpxchg 0[edx],ebx" \
			parm [edx] [eax] [ebx] \
			modify exact [eax] value [eax];

#pragma aux smp_locked_or =\
			"lock or [eax],edx"\
			parm [eax] [edx]\
			modify exact [ ];

#pragma aux smp_locked_and =\
			"lock and [eax],edx"\
			parm [eax] [edx]\
			modify exact [ ];

#else

#pragma aux insb = ".286p" "rep insb"\
    parm [es di] [cx] [dx] \
    modify [cx di] 

#pragma aux insw = ".286p" "rep insw"\
    parm [es di] [cx] [dx] \
    modify [cx di] 

#pragma aux outsb = ".286p" "rep outs dx,byte ptr es:[si]" \
    parm [es si] [cx] [dx] \
    modify nomemory exact [cx si]

#pragma aux outsw = ".286p" "rep outs dx,word ptr es:[si]" \
    parm [es si] [cx] [dx] \
    modify nomemory exact [cx si]

#pragma aux delay_8X = "here: loop here" parm nomemory [cx] modify nomemory exact [cx]

#pragma aux pswget = "pushf" "pop ax" parm nomemory [] modify nomemory [] value  [ax]
#pragma aux restore = "popf" parm routine nomemory [] modify nomemory exact [];
#pragma aux disable = "pushf" "pop ax" "cli" parm nomemory [] modify exact [ax] value [ax]
#pragma aux enable = "pushf" "sti" "pop ax" parm nomemory [] modify exact [ax] value [ax]
#pragma aux str_forward = "pushf" "cld" "pop ax" parm nomemory [] modify exact [ax] value [ax]
#pragma aux str_reverse = "pushf" "std" "pop ax" parm nomemory [] modify exact [ax] value [ax]

#pragma aux segsize = "lsl ax,ax" parm nomemory [ax] modify exact nomemory [ax] value [ax]
            
#pragma aux swapl = \
            "xchg al,ah" \
            "xchg dl,dh" \
            "xchg ax,dx" \
            parm nomemory [dx ax] \
            modify exact nomemory [dx ax] \
			value [dx ax]

#pragma aux memcpy8 =\
			"push ds" \
			"mov ds,dx" \
			"rep movsb" \
			"pop ds" \
			parm [es di] [dx si] [cx] \
			modify exact [si di cx]
    
#pragma aux memcpy16 =  \
			"push ds" \
			"mov ds,dx" \
			"shr cx,1" \
			"rep movsw" \
			"pop ds" \
			parm [es di] [dx si] [cx] \
			modify exact [si di cx]
    
#pragma aux memcpy32 =  \
			".386p" \
			"push ds" \
			"mov ds,dx" \
			"shr cx,2" \
			"rep movsd" \
			"pop ds" \
			parm [es di] [dx si] [cx] \
			modify exact [si di cx]

#endif

#endif
