/// <summary>
 /// Dump the Memory blocks that managed by Memory manager, this is debug function
 /// </summary>
 public void Dump()
 {
     Console.WriteLine("===================================================");
     foreach (KeyValuePair <ulong, IDDRMemoryBlock> kvp in _mAllocatedBlocks)
     {
         IDDRMemoryBlock b          = kvp.Value;
         ulong           endAddress = b.Address + b.SizeInBytes - 1;
         Console.WriteLine("{0:X8} ({0,4}) - {1:X8} ({1,4}) ({2} bytes); isAligned = {3}", b.Address, endAddress, b.SizeInBytes, b.IsP2PAligned);
     }
     Console.WriteLine("Available memory: {0} bytes; Max Block: {1} bytes", Available, MaxFreeBlock);
     Console.WriteLine("===================================================\n");
 }
        /// <summary>
        /// Update available memory stats.
        /// </summary>
        private void CalculateStats()
        {
            // see if it will fit after an existing block
            int   blockIndex          = 0;
            ulong freeSpaceBytesTotal = 0;
            ulong maxBlockBytes       = 0;

            if (_mAllocatedBlocks.Count == 0)
            {
                freeSpaceBytesTotal = maxBlockBytes = _mTotalSizeInBytes;
            }
            else
            {
                IDDRMemoryBlock block = _mAllocatedBlocks.Values[0];
                freeSpaceBytesTotal = maxBlockBytes = block.Address - _mBaseAddress;

                foreach (var kvp in _mAllocatedBlocks)
                {
                    block = kvp.Value;
                    ulong freeSpaceStart = block.Address + block.SizeInBytes;

                    blockIndex++;
                    ulong freeSpaceBytes;
                    if (blockIndex == _mAllocatedBlocks.Count)
                    {
                        // in this case, next block is past the end of memory
                        freeSpaceBytes = _mTotalSizeInBytes + _mBaseAddress - freeSpaceStart;
                    }
                    else
                    {
                        IDDRMemoryBlock nextBlock = _mAllocatedBlocks.Values[blockIndex];
                        freeSpaceBytes = nextBlock.Address - freeSpaceStart;
                    }

                    freeSpaceBytesTotal += freeSpaceBytes;
                    if (freeSpaceBytes > maxBlockBytes)
                    {
                        maxBlockBytes = freeSpaceBytes;
                    }

                    if (blockIndex == _mAllocatedBlocks.Count)
                    {
                        break; // error - no room
                    }
                }
            }
            _mAvailableBytes    = freeSpaceBytesTotal;
            _mMaxFreeBlockBytes = maxBlockBytes;
            _mStatsNeedUpdate   = false;
        }
        /// <summary>
        /// Allocates memory in the Measurement Accelerator FPGA module and returns a handle to it.
        /// </summary>
        /// <param name="sizeInBytes">Size in bytes</param>
        /// <param name="isP2PAligned">If true, allocate with Address alignment to support Peer to Peer transfer</param>
        /// <returns>Returns a memory block object containing the Address and related properties.  </returns>
        public IDDRMemoryBlock Allocate(ulong sizeInBytes, bool isP2PAligned)
        {
            if (sizeInBytes == 0)
            {
                throw new Exception("Invalid size argument.");
            }

            // adjust sizeInBytes to minimum alignment
            sizeInBytes = Align(sizeInBytes, MinAlignment);

            if (_mAllocatedBlocks.Count == 0)
            {
                if (sizeInBytes > _mTotalSizeInBytes)
                {
                    throw new Exception("Cannot allocate specified block of memory.");
                }

                return(AddNewBlock(_mBaseAddress, sizeInBytes, isP2PAligned));
            }
            else
            {
                // see if there is room at the top of memory
                IDDRMemoryBlock block = _mAllocatedBlocks.Values[0];
                if (sizeInBytes <= (block.Address - _mBaseAddress))
                {
                    return(AddNewBlock(_mBaseAddress, sizeInBytes, isP2PAligned));
                }
            }

            // see if it will fit after an existing block
            int blockIndex = 0;

            foreach (var kvp in _mAllocatedBlocks)
            {
                var   block = kvp.Value;
                ulong putativeStartAddress = block.Address + block.SizeInBytes;
                if (isP2PAligned)
                {
                    putativeStartAddress = Align(putativeStartAddress, P2PAlignment);
                }

                blockIndex++;
                ulong addressOfNextBlock;
                if (blockIndex == _mAllocatedBlocks.Count)
                {
                    // in this case, next block is past the end of memory
                    addressOfNextBlock = _mTotalSizeInBytes + _mBaseAddress;
                }
                else
                {
                    IDDRMemoryBlock nextBlock = _mAllocatedBlocks.Values[blockIndex];
                    addressOfNextBlock = nextBlock.Address;
                }

                if (((putativeStartAddress + sizeInBytes) <= addressOfNextBlock))
                {
                    return(AddNewBlock(putativeStartAddress, sizeInBytes, isP2PAligned));
                }

                if (blockIndex == _mAllocatedBlocks.Count)
                {
                    break; // error - no room
                }
            }

            throw new Exception("Cannot allocate specified block of memory.");
        }