/***************************************************************************************\

Module Name:    MtxMem.c

Description:    None.

References:     None.

    Copyright (c) 2000, Matrox Graphics Inc.
    All Rights Reserved.

\***************************************************************************************/


// --------------------------------------------------------------------------------------
//                               H E A D E R   F I L E S
// --------------------------------------------------------------------------------------

#include "precomp.h"

// --------------------------------------------------------------------------------------
//                        C O N S T A N T S   A N D   T Y P E S
// --------------------------------------------------------------------------------------
#define MEMHANDLE_GET_LINEAR(hMemory) ((void*)hMemory)

// --------------------------------------------------------------------------------------
//                           G L O B A L   V A R I A B L E S
// --------------------------------------------------------------------------------------

// --------------------------------------------------------------------------------------
//                  L O C A L   F U N C T I O N   P R O T O T Y P E S
// --------------------------------------------------------------------------------------

// --------------------------------------------------------------------------------------
//                         I N L I N E S   A N D   M A C R O S
// --------------------------------------------------------------------------------------

/***************************************************************************************\

Function:       memFileAlloc

Description:    None.

Parameters:     dwSize

Return Value:   void 
                None.

Comments:       None.

\***************************************************************************************/
MEMHANDLE memFileAlloc(DWORD dwSize, PSTR pszFileName, INT iLine)
{
    void* pvChunk;
  #ifdef MEMORY_STATS
    pvChunk = ClientMemStatsAlloc(dwSize + sizeof(DWORD), pszFileName, iLine);
  #else
    pvChunk = ClientMemAlloc(dwSize + sizeof(DWORD));
  #endif
    if (pvChunk)
    {
        /* First DWORD is used to store size of memory chunk */
        *(DWORD*)pvChunk = dwSize;

        return (MEMHANDLE) ((DWORD*)pvChunk + 1);
    }

    MTX_ERROR("in mtxvxd: failed to alloc memory\n");

    /* Allocation failed */
    return (MEMHANDLE) NULL;
}

/***************************************************************************************\

Function:       memFree

Description:    None.

Parameters:     dwSize

Return Value:   void 
                None.

Comments:       None.

\***************************************************************************************/
DWORD memFree(MEMHANDLE hMemory)
{
    void* pvAddress = (void*)((DWORD*)hMemory - 1);
    DWORD dwSize;
    
    /* Retrieve size from address pointer */
    dwSize = *(DWORD*)pvAddress;

    if (pvAddress && dwSize)
    {
        /* Retrieve size from address pointer */
      #ifdef MEMORY_STATS
        ClientMemStatsFree(pvAddress);
      #else
        ClientMemFree(pvAddress, dwSize + sizeof(DWORD));
      #endif
        return TRUE;
    }
    else
    {
        MTX_ERROR("in mtxvxd: failed to free memory\n");
    }

    return FALSE;
}

/***************************************************************************************\

Function:       memRead

Description:    Read from a physical memory resource.

Parameters:     hMem            Memory handle returned by memMap function.
                dwOffset        Offset from memory base
                pvBuffer        Address of output buffer
                dwSize          Size of output buffer

Return Value:   void 
                None.

Comments:       None.

\***************************************************************************************/
void memRead(MEMHANDLE hMemory, DWORD dwOffset, void* pvBuffer, DWORD dwSize)
{
    volatile void* pvDest;
    volatile void* pvSrc;
    DWORD  dwCount;

    dwCount = dwSize;
    pvDest = pvBuffer;
    pvSrc  = (volatile void*)((DWORD)MEMHANDLE_GET_LINEAR(hMemory) + dwOffset);

    while (dwCount)
    {
        if ((((DWORD)pvSrc & 3) == 0) && (dwCount >= sizeof(DWORD)))
        {
            volatile DWORD* pdwSrc = (volatile DWORD*)pvSrc;
            volatile DWORD* pdwDest = (volatile DWORD*)pvDest;
            
            pdwDest[0] = pdwSrc[0];
            
            pvSrc = (volatile void*)(pdwSrc + 1);
            pvDest = (volatile void*)(pdwDest + 1);

            dwCount -= sizeof(DWORD);
        }
        else if ((((DWORD)pvSrc & 1) == 0) && (dwCount >= sizeof(WORD)))
        {
            volatile WORD* pwSrc = (volatile WORD*)pvSrc;
            volatile WORD* pwDest = (volatile WORD*)pvDest;
            
            pwDest[0] = pwSrc[0];
            
            pvSrc = (volatile void*)(pwSrc + 1);
            pvDest = (volatile void*)(pwDest + 1);

            dwCount -= sizeof(WORD);
        }
        else
        {
            volatile BYTE* pbySrc = (volatile BYTE*)pvSrc;
            volatile BYTE* pbyDest = (volatile BYTE*)pvDest;
            
            pbyDest[0] = pbySrc[0];
            
            pvSrc = (volatile void*)(pbySrc + 1);
            pvDest = (volatile void*)(pbyDest + 1);

            dwCount -= sizeof(BYTE);
        }
    }
}

/***************************************************************************************\

Function:       memWrite

Description:    Write to a physical memory resource.

Parameters:     hMemory         Memory handle returned by memMap function
                dwOffset        Offset from memory base
                pvBuffer        Address of input buffer
                dwSize          Size of input buffer

Return Value:   void 
                None.

Comments:       None.

\***************************************************************************************/
void memWrite(MEMHANDLE hMemory, DWORD dwOffset, void* pvBuffer, DWORD dwSize)
{
    volatile void* pvDest;
    volatile void* pvSrc;
    DWORD  dwCount;

    dwCount = dwSize;
    pvDest = (volatile void*)((DWORD)MEMHANDLE_GET_LINEAR(hMemory) + dwOffset);
    pvSrc  = pvBuffer;

    while (dwCount)
    {
        if ((((DWORD)pvDest & 3) == 0) && (dwCount >= sizeof(DWORD)))
        {
            volatile DWORD* pdwSrc = (volatile DWORD*)pvSrc;
            volatile DWORD* pdwDest = (volatile DWORD*)pvDest;
            
            pdwDest[0] = pdwSrc[0];
            
            pvSrc = (volatile void*)(pdwSrc + 1);
            pvDest = (volatile void*)(pdwDest + 1);

            dwCount -= sizeof(DWORD);
        }
        else if ((((DWORD)pvDest & 1) == 0) && (dwCount >= sizeof(WORD)))
        {
            volatile WORD* pwSrc = (volatile WORD*)pvSrc;
            volatile WORD* pwDest = (volatile WORD*)pvDest;
            
            pwDest[0] = pwSrc[0];
            
            pvSrc = (volatile void*)(pwSrc + 1);
            pvDest = (volatile void*)(pwDest + 1);

            dwCount -= sizeof(WORD);
        }
        else
        {
            volatile BYTE* pbySrc = (volatile BYTE*)pvSrc;
            volatile BYTE* pbyDest = (volatile BYTE*)pvDest;
            
            pbyDest[0] = pbySrc[0];
            
            pvSrc = (volatile void*)(pbySrc + 1);
            pvDest = (volatile void*)(pbyDest + 1);

            dwCount -= sizeof(BYTE);
        }
    }
}
