#ifndef _ASSEMBLY_HPP_
#define _ASSEMBLY_HPP_
//                                        Ruler
//       1         2         3         4         5         6         7         8
//345678901234567890123456789012345678901234567890123456789012345678901234567890

    /********************************************************************/
    /*                                                                  */
    /*   The standard layout.                                           */
    /*                                                                  */
    /*   The standard layout for 'hpp' files for this code is as        */
    /*   follows:                                                       */
    /*                                                                  */
    /*      1. Include files.                                           */
    /*      2. Constants exported from the class.                       */
    /*      3. Data structures exported from the class.                 */
	/*      4. Forward references to other data structures.             */
	/*      5. Class specifications (including inline functions).       */
    /*      6. Additional large inline functions.                       */
    /*                                                                  */
    /*   Any portion that is not required is simply omitted.            */
    /*                                                                  */
    /********************************************************************/

#include "Global.hpp"
#pragma warning(disable: 4311 4312)

    /********************************************************************/
    /*                                                                  */
    /*   Constants exported from the class.                             */
    /*                                                                  */
    /*   The assembly constants indicate the location of the thread     */
    /*   local store.                                                   */
    /*                                                                  */
    /********************************************************************/

#define PcTeb                         0x18
#define IDTeb                         0x24

#ifdef WINDOWS_95
CONST SBIT32 TebSlot				  = 0x88;
#else
CONST SBIT32 TebSlot				  = 0xE10;
#endif

#ifndef ASSEMBLY_PREFETCH_SUPPORT
#define prefetcht0					  __asm _emit 0x0f __asm _emit 0x18 __asm _emit 0x08
#define prefetcht1					  __asm _emit 0x0f __asm _emit 0x18 __asm _emit 0x10
#define prefetcht2					  __asm _emit 0x0f __asm _emit 0x18 __asm _emit 0x18
#define prefetchnta					  __asm _emit 0x0f __asm _emit 0x18 __asm _emit 0x00
#endif

#pragma warning( disable : 4035 )

    /********************************************************************/
    /*                                                                  */
    /*   Assembly language for ultra high performance.                  */
    /*                                                                  */
    /*   We have coded a few functions in assembly language for         */
    /*   ultra high performance.                                        */
    /*                                                                  */
    /********************************************************************/

class ASSEMBLY
    {
    public:
        //
        //   Public inline functions.
        //
		ASSEMBLY( VOID )
			{ /* void */ }

		STATIC INLINE SBIT32 AtomicAdd
				( 
				VOLATILE SBIT32		  *Address,
				SBIT32				  Value 
				)
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov		ecx,Address					// Load the address.
				mov		eax,Value					// Load the value.
				lock	xadd dword ptr[ecx],eax		// Increment the value.
				}
#else
			return 
				(
				(SBIT32) InterlockedExchangeAdd
					( 
					((LPLONG) Address),
					((LONG) Value) 
					)
				);
#endif
			}

		STATIC INLINE SBIT32 AtomicCompareExchange
				( 
				VOLATILE SBIT32		  *Address,
				SBIT32				  NewValue,
				SBIT32				  Value 
				)
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov		ecx,Address					// Load the address.
				mov		edx,NewValue				// Load the new value.
				mov		eax,Value					// Load the value.
				lock	cmpxchg	dword ptr[ecx],edx	// Update the value.
				}
#else
			#if defined(_AMD64_)
			return(
				(SBIT32)InterlockedCompareExchange( 
					((volatile LONG*) Address),
					((LONG) NewValue),
					((LONG) Value)
				)
			);
			#else
			return(
				(SBIT32)InterlockedCompareExchange( 
					((VOID**) Address),
					((VOID*) NewValue),
					((VOID*) Value)
				)
			);
			#endif
#endif
			}
#ifdef ASSEMBLY_X86

		STATIC INLINE SBIT64 AtomicCompareExchange64
				( 
				VOLATILE SBIT64		  *Address,
				SBIT64				  NewValue,
				SBIT64				  Value 
				)
			{
			__asm
				{
				mov		esi, Address				// Load the adrress.
				mov		ebx, dword ptr NewValue[0]	// Load the new value.
				mov		ecx, dword ptr NewValue[4]	// Load the new value.
				mov		eax, dword ptr Value[0]		// Load the value.
				mov		edx, dword ptr Value[4]		// Load the value.
				lock	cmpxchg8b [esi]				// Update the value.
				}
			}
#endif

		STATIC INLINE SBIT32 AtomicDecrement( VOLATILE SBIT32 *Address )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov		ecx,Address					// Load the Address.
				mov		eax,-1						// Load constant.
				lock	xadd dword ptr[ecx],eax		// Decrement value.
				dec		eax							// Correct result.
				}
#else
			return ((SBIT32) InterlockedDecrement( ((LONG*) Address) ));
#endif
			}

		STATIC INLINE SBIT32 AtomicExchange
				( 
				VOLATILE SBIT32		  *Address,
				SBIT32				  NewValue 
				)
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov		ecx,Address					// Load the Address.
				mov		eax,NewValue				// Load the value.
				lock	xchg dword ptr[ecx],eax		// Exchange new value.
				}
#else
			return 
				(
				(SBIT32) InterlockedExchange
					( 
					((LONG*) Address),
					((LONG) NewValue) 
					)
				);
#endif
			}

		STATIC INLINE SBIT32 AtomicIncrement( VOLATILE SBIT32 *Address )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov		ecx,Address					// Load the Address.
				mov		eax,1						// Load constant.
				lock	xadd dword ptr[ecx],eax		// Increment value.
				inc		eax							// Correct result.
				}
#else
			return ((SBIT32) InterlockedIncrement( ((LONG*) Address) ));
#endif
			}

		STATIC INLINE SBIT32 GetThreadId( VOID )
			{
#ifdef ASSEMBLY_X86
#ifdef ENABLE_NON_STANDARD_ASSEMBLY
			__asm
				{
				mov		eax,fs:[PcTeb]				// Load TEB base address.
				mov		eax,dword ptr[eax+IDTeb]	// Load thread ID.
				}
#else
			return ((SBIT32) GetCurrentThreadId());
#endif
#else
			return ((SBIT32) GetCurrentThreadId());
#endif
			}

		STATIC INLINE VOID PrefetchL1( VOID *Address )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov			eax,Address				// Load Address.
#ifdef ASSEMBLY_PREFETCH_SUPPORT
				prefetcht0	[eax]					// Prefetch into the L1.
#else
				prefetcht0							// Prefetch into the L1.
#endif
				}
#endif
			}

		STATIC INLINE VOID PrefetchL2( VOID *Address )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov			eax,Address				// Load Address.
#ifdef ASSEMBLY_PREFETCH_SUPPORT
				prefetcht1	[eax]					// Prefetch into the L2.
#else
				prefetcht1							// Prefetch into the L2.
#endif
				}
#endif
			}

		STATIC INLINE VOID PrefetchL3( VOID *Address )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov			eax,Address				// Load Address.
#ifdef ASSEMBLY_PREFETCH_SUPPORT
				prefetcht2	[eax]					// Prefetch into the L3.
#else
				prefetcht2							// Prefetch into the L3.
#endif
				}
#endif
			}

		STATIC INLINE VOID PrefetchNta( VOID *Address )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov			eax,Address				// Load Address.
#ifdef ASSEMBLY_PREFETCH_SUPPORT
				prefetchnta	[eax]					// Prefetch into the L1.
#else
				prefetchnta							// Prefetch into the L1.
#endif
				}
#endif
			}

		STATIC INLINE SBIT32 GetFeatureMask( VOID )
			{
#ifdef ASSEMBLY_X86
			__asm
				{
				mov		eax,1						// Load CPUID feature ID.
				cpuid								// Get the CPU infomation.
				mov		eax,edx						// Feature mask return.
				}
#else
			return 0;
#endif
			}

#ifdef ASSEMBLY_X86
#ifdef ENABLE_NON_STANDARD_ASSEMBLY
		STATIC INLINE VOID *GetTlsAddress( SBIT32 TlsOffset )
			{
			__asm
				{
				mov		eax,TlsOffset				// Load TLS offset.
				add		eax,fs:[PcTeb]				// Add TEB base address.
				}
			}
#endif
#endif

		STATIC INLINE VOID *GetTlsValue( SBIT32 TlsIndex,SBIT32 TlsOffset )
			{
#ifdef ASSEMBLY_X86
#ifdef ENABLE_NON_STANDARD_ASSEMBLY
			__asm
				{
				mov		eax,TlsOffset				// Load TLS offset.
				add		eax,fs:[PcTeb]				// Add TEB base address.
				mov		eax,[eax]					// Load TLS value.
				}
#else
			return (TlsGetValue( ((DWORD) TlsIndex) ));
#endif
#else
			return (TlsGetValue( ((DWORD) TlsIndex) ));
#endif
			}

		STATIC INLINE VOID SetTlsValue
				( 
				SBIT32				  TlsIndex,
				SBIT32				  TlsOffset,
				VOID				  *NewPointer 
				)
			{
#ifdef ASSEMBLY_X86
#ifdef ENABLE_NON_STANDARD_ASSEMBLY
			__asm
				{
				mov		eax,TlsOffset				// Load TLS offset.
				add		eax,fs:[PcTeb]				// Add TEB base address.
				mov		edx,NewPointer				// Load new TLS value.
				mov		[eax],edx					// Store new TLS value.
				}
#else
			(VOID) TlsSetValue( ((DWORD) TlsIndex),NewPointer );
#endif
#else
			(VOID) TlsSetValue( ((DWORD) TlsIndex),NewPointer );
#endif
			}

		~ASSEMBLY( VOID )
			{ /* void */ }

	private:
        //
        //   Disabled operations.
        //
        ASSEMBLY( CONST ASSEMBLY & Copy );

        VOID operator=( CONST ASSEMBLY & Copy );
    };

#pragma warning( default : 4035 )
#endif
