/*****************************************************************************
**
**  Name: map.c
**
**  Description: This is the code for simple version of the Map Server
**
**  Status: PRELIMINARY
**
**  $Log:   S:/tbird/mt2_186/map/map.c_v  $
** 
**    Rev 1.1   26 Feb 1997 11:35:08   Judy
** 
**    Rev 1.0   16 Dec 1996 14:09:22   Judy
** Initial revision.
** 
**    Rev 1.30   20 Oct 1994 17:07:24   steve
** fix a bug of setting a map with target/ram type.
** 
**    Rev 1.29   20 Oct 1994 16:07:00   steve
** If there is no entry for a disabled map setting, just let it go and don't
** show any error message.
** 
**    Rev 1.28   10 Oct 1994 09:31:00   steve
** if fail to set a map, disable that SDS member.    --- kevin
** 
**    Rev 1.27   06 Oct 1994 10:54:30   ernie
** Restored PowerPack Intel space support.
** 
**    Rev 1.26   30 Sep 1994 16:43:40   steve
** Prevent any map operation when no overlay memory available
** 
**    Rev 1.25   07 Sep 1994 10:17:52   roy
** new fix(s) from Kevin
** 
**    Rev 1.24   29 Jun 1994 09:29:54   marilyn
** Fixed bug in writing the access rights to FW which included the
** target and overlay bit.  Target maps were being rejected by the FW.
** 
**    Rev 1.23   10 Jun 1994 10:54:52   joyce
** Kevin modified :
** 1. All addresses are created as PHYSICAL addresses.
** 2. Remove map->blockSize -= 1; from MapClear()
** 
**    Rev 1.22   02 Jun 1994 15:44:56   steve
** Kevin's changes for pv 2.2 beta 386 build 3
** 
**    Rev 1.21   24 May 1994 07:42:40   tom
** Merged 1.20.1.1 onto trunk (note:  1.20.2.0 still on branch).
** 
**    Rev 1.20.1.1   19 May 1994 10:17:20   tom
** 5/19/93 version from PDL.
** 
**    Rev 1.20   24 Nov 1992 15:06:40   john
** Enabled the cli map command to map blocks larger than the
** maxBlockSize of a single map block.  It now concatenates multiple
** blocks to fill the request.
**
**    Rev 1.19   04 Nov 1992 15:24:02   john
** Major changes in how map blocks are allocated.
** Map blocks can now only be set in 64,128,256,512K byte chunks.  And
** on like sized boundaries.  If a request is made that crosses these
** boundaries an attempt is made to map the block by using two
** sequential blocks.
**
**    Rev 1.18   21 Oct 1992 10:20:40   john
** Map commands now completely finish before allowing other processes to
** start.
** 
**    Rev 1.17   18 Sep 1992 09:21:20   john
** added code to prevent changing the map when emulating
** 
**    Rev 1.16   17 Sep 1992 11:52:26   john
** fixed bug when clearing map blocks
**
**    Rev 1.15   03 Sep 1992 14:15:34   john
** Changed name of map changed event to correspond to the new syntax.
** Modified set map to set start address according to map block size.
** This prevents HW contention caused by overlapping memory blocks.
** 
**    Rev 1.14   14 Aug 1992 13:08:50   john
** Changed the return status in MapBlockOveralp to better handle certain
** conditions.
** 
**    Rev 1.13   13 Aug 1992 11:40:24   john
** Removed many compile warnings caused by enabling all warning
** messages.
** Added code to read the current state of the HW when the dll is
** initialized.  This is done because the user could be restarting a
** debug session without resetting the emulator.
** 
**    Rev 1.12   04 Aug 1992 15:54:28   john
** moved GetMapPresent prototype to map.h
** 
**    Rev 1.11   01 Aug 1992 17:35:24   john
** changed mapblockoverlap to an EXPORT function
** 
**    Rev 1.10   31 Jul 1992 16:50:14   john
** The exported functions that were returning just a U32 were unusable
** by actor.  These functions were changed to return a RETCODE.  This
** caused these calls to be removed in other places in the code.
**
**    Rev 1.9   29 Jul 1992 13:59:40   john
** Made many changes.  Most having to do with correctly handling
** map block overlap, and keeping track of the order map blocks should
** be displayed.
** 
**    Rev 1.8   27 Jul 1992 13:33:08   john
** Added code to keep track of how the map blocks are ordered.
** Rewrote mapset, mapget, and mapclear.
** Added code to check for memory block overlaps.
** Added code to set the shared data members.
** Added code to reorder the map blocks after a block has been added/removed.
** 
**    Rev 1.7   22 Jul 1992 14:46:44   doug
** now tested
** 
**    Rev 1.6   22 Jul 1992 10:35:18   john
** Modified code to use the new shared data server.
** Removed 68030 specific references.
** Removed obsolete pmem.h include.
** Modified mapset/mapget/mapclear according to new shared data server.
** 
**    Rev 1.5   27 Feb 1992 15:26:32   doug
** Simple map interface
** 
**    Rev 1.4   04 Feb 1992 10:57:02   nghia
** !!! nothing change.
**
**    Rev 1.3   30 Jan 1992 15:04:12   jim
** Removed sdgen.h and replaced it with sdinit.h
**
**    Rev 1.2   23 Jan 1992 16:01:34   doug
** move CLI and added help command to CLI
**
**    Rev 1.1   20 Jan 1992 16:46:40   doug
** changed int EXPORT FAR PASCAL
**
**    Rev 1.0   14 Jan 1992 13:19:12   tom
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/map/map.c_v   1.1   26 Feb 1997 11:35:08   Judy  $
**
**  Copyright (C) 1991,1992 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#ifndef _ADDR_
#include "addr.h"
#endif


#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _BKROOT_
#include "bkroot.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _TRACE_
#include "trace.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _MAP_
#include "map.h"
#endif

#ifndef _MAPERR_
#include "maperr.h"
#endif

#ifndef _SDPROBE_
#include "sdprobe.h"
#endif

#ifndef _SSHARED_
#include "sshared.h"
#endif

#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif

#ifndef  _TBIRDMEM_
#include "tbirdmem.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

typedef enum {COLD_START,NORMAL_STATUS,DIAGNOSTIC_STATUS,HW_RESET_STATUS} FW_STATUS;
U32 mapBlockCount;      /* number of HW map blocks */
U32 mapBlockSize;       /* largest size for a HW block */
U32 mapBlockGranularity;   /* minimum size for a HW block */
PRIVATE BOOLEAN mapPresent;

U32 *mapOrder = NULL;


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern RETCODE CreateAddress(DESCRIPTOR *);
extern PROC_SYSTEM_TYPE gSystemType;
extern SPACE_TYPE gSpaceType;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

RETCODE UpdateMapOrder(MEMORY_MAP_DATA map);
RETCODE WriteMapMembers(MEMORY_MAP_DATA map);
RETCODE SetMapPresent(BOOLEAN present);
RETCODE FreeMapEntry(U32 *freeEntry);
RETCODE ProcessMapAddress( MEMORY_MAP_DATA *memMap, U32 *bsize1, U32 *bsize2,
                           U16 *numBlocks);
RETCODE ProcessBlockOrder (U32 offset, U32 *blockSize1, 
                           U32 *blockSize2, U16 *numBlocks);
RETCODE SpaceOrder(U8 mapSpace, U8 cmpSpace);
RETCODE EXPORT GetMapFromFirmware(VOID);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/****************************************************************************
**
**  FreeMapEntry
**
*****************************************************************************/
RETCODE FreeMapEntry(U32 *freeEntry) {
   U16 i;
   MEMORY_MAP_DATA map;
   RETCODE err;
   
   if ((err = CreateAddress(&map.address)) != GOOD)
      return(err);
   for (i=0; i<(U16)mapBlockCount; i++) {
      map.blockNumber = i;
      if ((err = MapGet(&map)) != GOOD) {
         AdrDestroyAddress(map.address);
         return(err);
      }
      if (map.enabled == MAP_DISABLE) {
         err = AdrDestroyAddress(map.address);
         *freeEntry = i;  
         return(err);
      }
   }
   AdrDestroyAddress(map.address);
   *freeEntry = DUMMY_MAP_ORDER;
   return(ER_NO_FREE_MAP_BLOCKS);
}

/****************************************************************************
**
**  GetMapBlockCount
**
*****************************************************************************/
RETCODE EXPORT GetMapBlockCount(WORD *blockCount) {
   *blockCount = (WORD) mapBlockCount;
   return(GOOD);
}

/****************************************************************************
**
**  GetMapBlockGranularity
**
*****************************************************************************/
RETCODE EXPORT GetMapBlockGranularity(U32 *blockGran) {
   *blockGran = mapBlockGranularity;
   return(GOOD);
}

/****************************************************************************
**
**  GetMapBlockSize
**
*****************************************************************************/
RETCODE EXPORT GetMapBlockSize(U32 *blockSize) {
   *blockSize = mapBlockSize;
   return(GOOD);
}

/****************************************************************************
**
**  GetMapPresent
**
*****************************************************************************/
BOOLEAN EXPORT GetMapPresent(VOID) {
   return(mapPresent);
}

/****************************************************************************
**
**  SetMapPresent
**
*****************************************************************************/
RETCODE SetMapPresent(BOOLEAN present) {
   mapPresent = present;
   return(GOOD);
}

/****************************************************************************
**
**  InitServer
**
*****************************************************************************/
RETCODE EXPORT InitServer(VOID) {
   RETCODE err;
   U16 i;
   MEMORY_MAP_DATA map;

   /* get the number of map blocks provided by the hardware */
   ProcReturnSystemType(&gSystemType);
   if((err = SdnReadMember(SDN_NUM_MAP_BLOCKS, (U8 FAR *)&mapBlockCount))
      != GOOD) return(err);
   if (mapBlockCount == 0) SetMapPresent(FALSE);
   
   if (mapBlockCount > 16) mapBlockCount = 16;

   /* strip the upper 16 bits, they cannot be compared later anyway */
   mapBlockCount &= 0xFFFFL;
   /* get the size of the map blocks */
   if((err = SdnReadMember(SDN_SIZE_MAP_BLOCK, (U8 FAR *)&mapBlockSize))
      != GOOD) return(err);
   /* get the granularity of the map blocks */
   if((err = SdnReadMember(SDN_GRAN_MAP_BLOCK,(U8 FAR *)&mapBlockGranularity))
      != GOOD) return(err);

   if (mapOrder == NULL) {
      if (mapBlockCount) {
         if((mapOrder = (U32 *)TMalloc(mapBlockCount * sizeof(U32))) == NULL)
            return(ER_OUT_OF_MEMORY);
         /* initialize the block ordering */
         for (i=0;i< (U16) mapBlockCount;i++) mapOrder[i] = DUMMY_MAP_ORDER;
         SetMapPresent(TRUE);
      } else {
         SetMapPresent(FALSE);
      }

      if ((err = CreateAddress(&map.address)) != GOOD)
         return(err);
      for (i=0; i < (U16)mapBlockCount; i++) {
         map.blockNumber = i;
         if ((err = MapGet(&map)) != GOOD) {
            AdrDestroyAddress(map.address);
            return(err);
         }
         if (map.enabled) {
            if ((err = UpdateMapOrder(map)) != GOOD) {
               AdrDestroyAddress(map.address);
               return(err);
            }
         }
      }
   }
   GetMapFromFirmware();
   return(GOOD);
}

/****************************************************************************
**
**  MapSet
**
*****************************************************************************/
RETCODE EXPORT MapSet(MEMORY_MAP_DATA *memMap) {
   struct MINFO {
      U32 offset;
      U32 size;
      U32 number;
   } *mInfo;
   RETCODE err;
   U32 offset, bsize1, bsize2;
   MAP_BLOCK status;
   U16 numBlocks, i, numMapSetting, numRequiredBlocks;

   if (GOOD != (err = BkProcessorMustBeHalted()))  /* check for emu running */
      return err;

   if (!GetMapPresent()) return(ER_NO_MEMORY_PRESENT);

   // if the memory type and access are TARGET and RAM, respectively,
   // disable the setting.
   // The combination of target (bit7 is on) and ram (bit 0 and bit 1 are
   // off) should be 0x0080.
   if ((memMap->accessRights&(0x00ff)) == 0x0080) { 
      memMap->enabled = MAP_DISABLE;
      memMap->accessRights &= 0xFF7F; // get rid of target bit (bit 7)
   }


   /**************** Only for MICEpack and PowerPack-E3X *******************/
   if (gSystemType == PROC_MICEPACK ||
       (gSystemType == PROC_POWERPACK && gSpaceType == SP_INTEL)) {

      if((err = AdrGetAddrOffset(memMap->address, (U32 FAR *)&offset))
            != GOOD)
         return(err);
      if ((err = MapBlockOverlap(memMap, offset, &status)) != GOOD)
         return(err);
      switch (status) {
         case MAP_BLOCK_ALREADY_MAPPED:
         case MAP_ENTRY_FOUND:
         case MAP_BLOCKS_IDENTICAL:
            err = ER_BLOCK_ALREADY_MAPPED;
            break;
         case MAP_NO_FREE_BLOCKS:
            err = ER_NO_FREE_MAP_BLOCKS;
            break;
         case MAP_ENTRY_NOT_FOUND:
            if ((err = FreeMapEntry(&memMap->blockNumber)) == GOOD)
               if ((err = WriteMapMembers(*memMap)) == GOOD)
                  err = UpdateMapOrder(*memMap);
            break;
         case MAP_ENTRY_CLEAR: //disable 
            if ((err = WriteMapMembers(*memMap)) == GOOD)
               err = UpdateMapOrder(*memMap);
            break;
      }
      return(err);
   }
   /******************        End        **********************/

   /* check for a map block overlap */
   bsize1 = memMap->blockSize;
   if ((err=ProcessMapAddress(memMap, &bsize1, &bsize2, &numBlocks)) != GOOD)
      return(err);

   if((err = AdrGetAddrOffset(memMap->address, (U32 FAR *)&offset))!= GOOD)
      return(err);

   if ((mInfo = (struct MINFO *)TMalloc(numBlocks * sizeof(struct MINFO)))
       == NULL)
      return(ER_OUT_OF_MEMORY);

   mInfo[0].offset = offset;
   mInfo[0].size = bsize1;
   offset += bsize1;
   if (numBlocks > 1) {
      mInfo[numBlocks-1].offset = offset + (numBlocks-2) * mapBlockSize;
      mInfo[numBlocks-1].size = bsize2;
   }

   for (i=1; i<numBlocks-1; i++) {
      mInfo[i].offset = offset;
      mInfo[i].size = mapBlockSize;
      offset += mapBlockSize;
   }

   numRequiredBlocks = 0;
   for (i=0; i<numBlocks; i++) {
      memMap->blockSize = mInfo[i].size;
      err = AdrSetAddrOffset(memMap->address, mInfo[i].offset);

      if (err == GOOD)
         err = MapBlockOverlap(memMap, mInfo[i].offset, &status);

      if (err == GOOD)
         switch (status) {
            case MAP_BLOCK_ALREADY_MAPPED:
            case MAP_ENTRY_FOUND:
               err = ER_BLOCK_ALREADY_MAPPED;
               break;
            case MAP_NO_FREE_BLOCKS:
               err = ER_NO_FREE_MAP_BLOCKS;
               break;
            case MAP_ENTRY_NOT_FOUND:
               mInfo[i].number = memMap->blockNumber;
               numRequiredBlocks++;
               break;
            case MAP_ENTRY_CLEAR:
               if ((err = WriteMapMembers(*memMap)) == GOOD)
                  err = UpdateMapOrder(*memMap);
               break;
            case MAP_BLOCKS_IDENTICAL:
               mInfo[i].number = DUMMY_MAP_ORDER;
               break;
         }
      if (err != GOOD) {
         TFree((LPSTR)mInfo);
         return(err);
      }
   }

   GetNumMapSetting(&numMapSetting);
   if ((mapBlockCount-numMapSetting) >= numRequiredBlocks) {
      err = GOOD;
      for (i=0; i<numBlocks; i++) {
         if (mInfo[i].number == DUMMY_MAP_ORDER)
            continue;
         memMap->blockSize = mInfo[i].size;
         if ((err = FreeMapEntry(&memMap->blockNumber)) == GOOD)
            err = AdrSetAddrOffset(memMap->address, mInfo[i].offset);
         if (err == GOOD)
            err = WriteMapMembers(*memMap);
         if (err == GOOD)
            err = UpdateMapOrder(*memMap);
         if (err != GOOD) {
            TFree((LPSTR)mInfo);
            return(err);
         }
      }
   }
   else
      err = ER_NO_FREE_MAP_BLOCKS;

   TFree((LPSTR)mInfo);
   return(err);
}

/****************************************************************************
**
**  MapSetWithIndex
**
*****************************************************************************/
RETCODE EXPORT MapSetWithIndex(MEMORY_MAP_DATA *mapInfo, U32 dwIndex)
{
   mapInfo->blockNumber = mapOrder[(U16)dwIndex];
   return MapSet(mapInfo);
}


/****************************************************************************
**
**  MapGet
**
*****************************************************************************/
RETCODE EXPORT MapGet(MEMORY_MAP_DATA *mapInfo) {
   RETCODE err;
   DESCRIPTOR desc;
   MEMBER_NAME name[SD_MAX_NAME];
   U32 offset;

   if (!GetMapPresent()) return(ER_NO_MEMORY_PRESENT);

   if (mapInfo->blockNumber > NUM_MAP_ENTRIES) return(ER_BLOCK_OUT_OF_RANGE);

   /* get all of the map entry information */
   wsprintf(name, "%s %d", SD_MAP_ENABLE, mapInfo->blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdReadMember(desc, (U8 *)&mapInfo->enabled)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   wsprintf(name, "%s %d", SD_MAP_PROTECT, mapInfo->blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdReadMember(desc, (U8 *)&mapInfo->accessRights)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   wsprintf(name, "%s %d", SD_MAP_ADDR, mapInfo->blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdReadMember(desc, (U8 *)&offset)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   if ((err = AdrSetAddrOffset(mapInfo->address, offset)) != GOOD)
      return(err);

   wsprintf(name, "%s %d", SD_MAP_LENGTH, mapInfo->blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdReadMember(desc, (U8 *)&mapInfo->blockSize)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   return(GOOD);
}

/****************************************************************************
**
**  MapGetWithIndex
**
*****************************************************************************/
RETCODE EXPORT MapGetWithIndex(MEMORY_MAP_DATA *mapInfo, U16 nIndex)
{
   mapInfo->blockNumber = mapOrder[nIndex];
   return MapGet(mapInfo);
}

/****************************************************************************
**
**  MapClear
**
*****************************************************************************/
RETCODE EXPORT MapClear(VOID) {
   RETCODE err;
   U16 i=0;
   MEMORY_MAP_DATA map;
   
   if (!GetMapPresent()) return(ER_NO_MEMORY_PRESENT);
   
   if ((err = CreateAddress(&map.address)) != GOOD)
       return(err);

   /* sequence through all enabled map blocks */
   /* as the map blocks are disabled the remaining enabled blocks */
   /* numbers in mapOrder will be shifted down to mapOrder[0]. */
   /* when mapOrder[0] no longer has a valid number in it the blocks have */
   /* been completely cleared */
   while((mapOrder[0] != DUMMY_MAP_ORDER) && (i < (U16) mapBlockCount)) {
      map.blockNumber = mapOrder[0];
      if ((err = MapGet(&map)) != GOOD) {
         AdrDestroyAddress(map.address);
         return(err);
      }
      map.enabled = MAP_DISABLE;
      //map.blockSize -= 1L;
      // ancestor masked a bug from upper stream, but the bug didn't exist
      // any more.
      if ((err = MapSet(&map)) != GOOD) {
         AdrDestroyAddress(map.address);
         return(err);
      }
      i++;
   }
   if ((err = AdrDestroyAddress(map.address)) != GOOD) return(err);
   
   return(GOOD);
}

/****************************************************************************
**
**  GetNumMapSetting
**
*****************************************************************************/
RETCODE EXPORT GetNumMapSetting(U16 *num)
{
   RETCODE err;
   DESCRIPTOR desc;
   MEMBER_NAME name[SD_MAX_NAME];
   U8 enabled, numMap, i;

   if (mapBlockCount == 0) {
      *num = 0;
      return(ER_NO_MEMORY_PRESENT);
   }
   *num = numMap = 0;
   while((mapOrder[*num] != DUMMY_MAP_ORDER) && (*num < (U16) mapBlockCount))
      (*num)++;

   if (gSystemType == PROC_POWERPACK) {
      // check the actual number of settings in SDS
      for (i=0; i<mapBlockCount; i++) {
         wsprintf(name, "%s %d", SD_MAP_ENABLE, i);
         if ((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
            return(err);
         if ((err = SdReadMember(desc, (U8 *)&enabled)) != GOOD)
            return(err);
         if ((err = SdUnRegister(desc)) != GOOD)
            return(err);
         if (enabled == MAP_ENABLE) numMap++;
      }
      if (numMap != *num) {
         if (numMap != 0)
            return(ER_ASSERTION);
         else {
            for (i=0; i<mapBlockCount; i++)
               mapOrder[i] = DUMMY_MAP_ORDER;
            *num = numMap;
         }
      }
   }

   return(GOOD);
}

/****************************************************************************
**
**  MapBlockOverlap
**
*****************************************************************************/
RETCODE EXPORT MapBlockOverlap(MEMORY_MAP_DATA *map, U32 offset,
                               MAP_BLOCK *status) {
   RETCODE err;
   U16 i;
   MEMORY_MAP_DATA cmpMap;
   U32 cmpOffset;
   U8 mapSpace, cmpSpace, mapAccess, cmpAccess, bMixSpace;

   if ((err = CreateAddress(&cmpMap.address))
      != GOOD) return(err);
   i = 0;
   while (i < (U16) mapBlockCount) {
      if (mapOrder[i] != DUMMY_MAP_ORDER) {
         /* there is a valid map entry */
         cmpMap.blockNumber = mapOrder[i];
         if ((err = MapGet(&cmpMap)) != GOOD) {
            AdrDestroyAddress(cmpMap.address);
            return(err);
         }
         if ((err = AdrGetAddrOffset(cmpMap.address, &cmpOffset)) != GOOD) {
            AdrDestroyAddress(cmpMap.address);
            return(err);
         }
         /* if the offsets are identical then there should only be one */
         /* block that matches.  If the block number is the same then it */
         /* is a match.  In the event of a match, we need to determine */
         /* if the block size is being changed, the access rights are being */
         /* changed, or if the map is being disabled */
         if (gSpaceType != SP_NONE) { 
            mapSpace  = (map->accessRights & 0xff00) >> 8;
            mapAccess = map->accessRights & 0x00ff;
            cmpSpace  = (cmpMap.accessRights & 0xff00) >> 8;
            cmpAccess = cmpMap.accessRights & 0x00ff;
         }
         else {
            mapSpace = cmpSpace = 0;
            mapAccess = map->accessRights;
            cmpAccess = cmpMap.accessRights; 
         }
         if (mapSpace != cmpSpace) {
            bMixSpace = mapSpace & cmpSpace;
            if (!bMixSpace) {
              // no intersection between the space modes
              i++;
              continue;
            }
         }
         else
            bMixSpace = 0;  // same space mode

         if (offset == cmpOffset) {
            if (bMixSpace) { // have some spaces joined
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_BLOCK_ALREADY_MAPPED;
               map->blockNumber = mapOrder[i];
               return(GOOD);
            }

            // same space
            if (map->enabled == cmpMap.enabled) {
               if (map->blockSize == cmpMap.blockSize) {
                  /* address range is identical */
                  if (mapAccess == cmpAccess) {
                     AdrDestroyAddress(cmpMap.address);
                     *status = MAP_BLOCKS_IDENTICAL;
                     map->blockNumber = mapOrder[i];
                     return(GOOD);
                  } else {  // different access rights
                     /* map blocks are different, force the block to be */
                     /* cleared first before modifying the attributes */
                     AdrDestroyAddress(cmpMap.address);
                     *status = MAP_ENTRY_FOUND;
                     map->blockNumber = mapOrder[i];
                     return(GOOD);
                  }
               } else { // different blocksize 
                  /* !!! just return an error for now */
                  /* the block size is different.  Determine if the */
                  /* block size can be safely increased/decreased.  */
                  /* All other parameters are a don't care since the */
                  /* block is already being changed. */
                  AdrDestroyAddress(cmpMap.address);
                  *status = MAP_BLOCK_ALREADY_MAPPED;
                  map->blockNumber = mapOrder[i];
                  return(GOOD);
               }
            } else {  // Disable it!
               /* map is being disabled */
               AdrDestroyAddress(cmpMap.address);
               if (map->blockSize >= cmpMap.blockSize) {
                  *status = MAP_ENTRY_CLEAR;
                  map->accessRights = cmpMap.accessRights;
               }
               else
                  *status = MAP_BLOCK_ALREADY_MAPPED;
               map->blockNumber = mapOrder[i];
               return(GOOD);
            }
         }
         if (offset < cmpOffset) {
            if ((offset+map->blockSize-1L) < cmpOffset) {   // no overlap
               U32 entry;

               if (FreeMapEntry(&entry) == GOOD) {
                  /* address range below the first mapped block */
                  /* go ahead and map it */
                  AdrDestroyAddress(cmpMap.address);
                  *status = MAP_ENTRY_NOT_FOUND;
                  map->blockNumber = entry;
                  return(GOOD);
               } else {
                  AdrDestroyAddress(cmpMap.address);
                  *status = MAP_NO_FREE_BLOCKS;
                  map->blockNumber = entry;
                  return(GOOD);
               }
            }
            else {  // has overlap area ==> fail
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_BLOCK_ALREADY_MAPPED;
               map->blockNumber = mapOrder[i];
               return(GOOD);
            }
         }
         if (offset > cmpOffset) {
            if ((cmpOffset+cmpMap.blockSize-1L) < offset) {   // no overlap
               i++;
               continue;
            }
            else {  // has overlap area ==> fail
               /* starting address is inside the block range of the */
               /* previous map block and is, therefore, invalid */
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_BLOCK_ALREADY_MAPPED;
               map->blockNumber = mapOrder[i];
               return(GOOD);
            }
         }
      } else {  // mapOrder[i] == DUMMY_MAP_ORDER
         /* find out if this is the first or the last entry */
         if (i == 0) {
            U32 entry;
            if (FreeMapEntry(&entry) == GOOD) {
               /* there are no map blocks */
               /* go ahead and map it */
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_ENTRY_NOT_FOUND;
               map->blockNumber = entry;
               return(GOOD);
            } else {
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_NO_FREE_BLOCKS;
               map->blockNumber = entry;
               return(GOOD);
            }
         }
         /* it is the last block so compare the offsets to the last 
            mapped block */
         cmpMap.blockNumber = mapOrder[i-1];
         if ((err = MapGet(&cmpMap)) != GOOD) {
            AdrDestroyAddress(cmpMap.address);
            return(err);
         }
         if ((err = AdrGetAddrOffset(cmpMap.address, &cmpOffset)) != GOOD) {
            AdrDestroyAddress(cmpMap.address);
            return(err);
         }
         if (gSpaceType != SP_NONE) {
            mapSpace  = (map->accessRights & 0xff00) >> 8;
            mapAccess = map->accessRights & 0x00ff;
            cmpSpace  = (cmpMap.accessRights & 0xff00) >> 8;
            cmpAccess = cmpMap.accessRights & 0x00ff;
         }
         else {
            mapSpace = cmpSpace = 0;
            mapAccess = map->accessRights;
            cmpAccess = cmpMap.accessRights; 
         }
         // check space mode first, if within same spaces, then do
         // comparison of these two blocks.
         if (mapSpace == cmpSpace) {
            /* check the range of the last block before adding the new block */
            if (offset > cmpOffset+cmpMap.blockSize-1L) {
               U32 entry;
               if (FreeMapEntry(&entry) == GOOD) {
                  /* add the new block */
                  AdrDestroyAddress(cmpMap.address);
                  *status = MAP_ENTRY_NOT_FOUND;
                  map->blockNumber = entry;
                  return(GOOD);
               } else {
                  AdrDestroyAddress(cmpMap.address);
                  *status = MAP_NO_FREE_BLOCKS;
                  map->blockNumber = entry;
                  return(GOOD);
               }
            } else {
               /* starting address inside the previous blocks range */
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_BLOCK_ALREADY_MAPPED;
               map->blockNumber = mapOrder[i-1];
               return(GOOD);
            }
         }
         else {  
            U32 entry;
            if (FreeMapEntry(&entry) == GOOD) {
               /* add the new block */
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_ENTRY_NOT_FOUND;
               map->blockNumber = entry;
               return(GOOD);
            } else {
               AdrDestroyAddress(cmpMap.address);
               *status = MAP_NO_FREE_BLOCKS;
               map->blockNumber = entry;
               return(GOOD);
            }
         }
      }
      i++;
   }
   /* There are no free blocks. */
   AdrDestroyAddress(cmpMap.address);
   *status = MAP_NO_FREE_BLOCKS;
   map->blockNumber = 0;
   return(GOOD);
}


/****************************************************************************
**
**  ProcessBlockOrder
**
*****************************************************************************/
RETCODE ProcessBlockOrder (U32 offset, U32 *bsize1,
                           U32 *bsize2, U16 *numBlocks) {
   U32 result;

   if (*bsize1 == 0) {
      *numBlocks = *bsize2 = 0;
      return (GOOD);
   }
   result = offset & (mapBlockSize - 1);
   if (result == 0) {
      if (*bsize1 >= mapBlockSize) {
         *bsize2 = *bsize1 - mapBlockSize;
         *bsize1 = mapBlockSize;
      }
      else
         *bsize2 = 0;
   }
   else {
      *bsize2 = *bsize1 - result;
      *bsize1 = result;
   }
   *numBlocks = *bsize2 / mapBlockSize;
   if (*bsize2 > 0) {
      if (*bsize2 % mapBlockSize) {
         (*numBlocks)++;
         *bsize2 %= mapBlockSize;
      }
      else
         *bsize2 = mapBlockSize;
   }
   (*numBlocks)++;

   return(GOOD);
}

/****************************************************************************
**
**  ProcessMapAddress
**
*****************************************************************************/
RETCODE ProcessMapAddress( MEMORY_MAP_DATA *memMap, U32 *bsize1, U32 *bsize2,
                           U16 *numBlocks) {
   RETCODE err;
   U32 offset;

   /* due to the hard coded nature of ProcessBlockOrder the following */
   /* check only protects against too large a request when mapBlockCount=2 */
   if (memMap->blockSize > (mapBlockCount * mapBlockSize))
      return(ER_BLOCK_TOO_LARGE);

   /* calculate the size of the map block in closest granularity size */
   if (memMap->blockSize & (mapBlockGranularity-1))
      memMap->blockSize = ((memMap->blockSize & ~(mapBlockGranularity-1)) +
         mapBlockGranularity);


   /* force sztarting offset to the nearest acceptable boundary */
   if((err = AdrGetAddrOffset(memMap->address, (U32 FAR *)&offset)) != GOOD)
      return(err);
   offset &= ~(mapBlockGranularity - 1);

   if((err = AdrSetAddrOffset(memMap->address, offset)) != GOOD)
      return(err);

   *bsize1 = memMap->blockSize;
   if ((err = ProcessBlockOrder(offset, bsize1, bsize2, numBlocks)) != GOOD)
      return(err);

   memMap->blockSize = *bsize1;

   return(GOOD);
}

/****************************************************************************
**
**  WriteMapMembers
**
*****************************************************************************/
RETCODE WriteMapMembers(MEMORY_MAP_DATA map) {
   RETCODE err;
   MEMBER_NAME name[SD_MAX_NAME];
   DESCRIPTOR desc;
   U32 offset, maxOffset;
   BOOLEAN timedOut;
   U8 mapCmd = TRUE;

   // check the max. offset
   if ((err = CreateAddress(&desc)) != GOOD)
      return(err);
   if ((err = AdrGetMaxInputAddrOffset(desc, &maxOffset)) != GOOD) {
      AdrDestroyAddress(desc);
      return(err);
   }
   AdrDestroyAddress(desc);
   maxOffset = maxOffset - map.blockSize + 1;

   // guarantee offset+map.blockSize-1 isn't greater than maxOffset
   if ((err = AdrGetAddrOffset(map.address, &offset)) != GOOD) return(err);
   if (offset > maxOffset)
      return(ER_ADR_ADDRESS_TOO_LARGE);

   /* write out all of the map entry information */
   /* write out the access rights */
   wsprintf(name, "%s %d", SD_MAP_PROTECT, map.blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdWriteMember(desc, (U8 *)&map.accessRights, GOOD)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   /* set the blocks starting address */
   if ((err = AdrGetAddrOffset(map.address, &offset)) != GOOD) return(err);
   wsprintf(name, "%s %d", SD_MAP_ADDR, map.blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdWriteMember(desc, (U8 *)&offset, GOOD)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   /* write the block size.  This will cause all entries to be updated */
   wsprintf(name, "%s %d", SD_MAP_LENGTH, map.blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdWriteMember(desc, (U8 *)&map.blockSize, GOOD)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   wsprintf(name, "%s %d", SD_MAP_ENABLE, map.blockNumber);
   if((err = SdRegister(name, NULLPTR, &desc)) != GOOD)
      return(err);
   if((err = SdWriteMember(desc, (U8 *)&map.enabled, GOOD)) != GOOD)
      return(err);
   if((err = SdUnRegister(desc)) != GOOD) return(err);

   if((err = SdnWriteCmdReadResponse(SDN_MAP_COMMAND + map.blockNumber,
      (VOID FAR *)&mapCmd, GOOD, SDN_MAP_RESULTS + map.blockNumber, 0,
      &timedOut)) != GOOD) {
      // disable the SDS member
      wsprintf(name, "%s %d", SD_MAP_ENABLE, map.blockNumber);
      if (SdRegister(name, NULLPTR, &desc) != GOOD)
         return(err);
      map.enabled = MAP_DISABLE;
      SdWriteMember(desc, (U8 *)&map.enabled, GOOD);
      SdUnRegister(desc);

      return(err);
   }
   /* notify the other servers the map has been changed */
   if((err = EnlEventNotify(EVENT_MAP_EDIT))!=GOOD) return(err);
   if((err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE)) != GOOD)
      return(err);
   return(GOOD);

}

/****************************************************************************
**
**  SpaceOrder
**
**  Description:
**     step 1: convert user|smm|up|ud|sp|sd into smm|user|sp|sd|up|ud
**     step 2: compare mapSpace' with cmpSpace'
**             GOOD if mspSpace' < cmpSpace'
**
**  Parameters:
**     input:
**        mapSpace: current space
**        cmpSpace: compared space
**
**     output:
**        (reture code): GOOD if correct order
**
*****************************************************************************/
RETCODE SpaceOrder(U8 mapSpace, U8 cmpSpace) {

   if (mapSpace == cmpSpace) return(GOOD);

   // Intel case:
   // bit 5: SMM, bit6: User
   if ((mapSpace&0xf0 || cmpSpace&0xf0) && (mapSpace < cmpSpace))
      return(GOOD);

   // Motorola cases:
   // Due to "SP" or "SD" > "UP" or "UD", compare the lowest two bits first
   if ((mapSpace&0x03) < (cmpSpace&0x03))  // compare SP, SD first
      return(GOOD);

   if ((mapSpace&0x03) == (cmpSpace&0x03))  // bit1, bit 0 ==> SP, SD
      if ((mapSpace&0x0c) < (cmpSpace&0x0c))  // bit3, bit 2 ==> UP, UD
         return(GOOD);

   return(!GOOD);
}

/****************************************************************************
**
**  UpdateMapOrder
**
**  Description:
**     Maintains an array that orders the individual map blocks in address
**     ascending order.
**     (ie if block0 = 10000-1ffff and block1 = 0-ffff then the ordered
**      array will hold   [1,0,ffffffff,ffffffff] (assuming four map blocks))
**
**  Parameters:
**     input:
**        map: map structure of the block entry to update
**
**     output:
**        (err): error code
**
*****************************************************************************/
RETCODE UpdateMapOrder(MEMORY_MAP_DATA map) {
   RETCODE err;
   U32 numEntries, cmpOffset, mapOffset;
   U16 i=0, entry;
   BOOLEAN done=FALSE, found = FALSE;
   MEMORY_MAP_DATA checkMap;
   U8 mapSpace, cmpSpace, mapAccess, cmpAccess;

   /* find out how many entries are active */
   if (mapOrder[i] == DUMMY_MAP_ORDER) {
      /* there are no entries */
      numEntries = 0L;
   } else {
      /* find out how many blocks are mapped */
      numEntries = i = 1L;
      while (i < (U16) mapBlockCount && !done) {
         if (mapOrder[i] != DUMMY_MAP_ORDER) {
            numEntries++;
            i++;
         } else {
            done = TRUE;
         }
      }
   }
   
   done = FALSE;
   if (map.enabled == MAP_ENABLE) {
      /* insert the block number into the ordering list */
      if (numEntries) {
         /* insert into the list */
         
         /* check the map address versus the block address */
         if ((err = CreateAddress(&checkMap.address)) != GOOD)
            return(err);
         if ((err = AdrGetAddrOffset(map.address, &mapOffset)) != GOOD) 
            return(err);

         if (gSpaceType != SP_NONE) {
            mapSpace  = (map.accessRights&0xff00) >> 8;
            // The following statements with /*!!none!!*/ command shows
            // the order of access rights have been changed as follows:  
            // ram, rombrk, rom, none ==> none, ram, rombrk, rom, none
            mapAccess = ((map.accessRights&0x007f)+1) % 4;
         }
         else {
            mapSpace = 0;
            // mapAccess = map.accessRights;
            /*!!none!!*/ //"none" < "ram" < "rom brk" < "rom nobrk"
            mapAccess = ((map.accessRights&0x007f)+1) % 4;
         }
         // add memory type (bit 7) information
         mapAccess |= (map.accessRights & 0x0080);

         i=0;
         /* find the location in the ordered list to insert the */
         /* block number */
         while ((i < (U16) mapBlockCount) && !done) {
            if (mapOrder[i] != DUMMY_MAP_ORDER) {
               /* compare the address of the smallest address range */
               checkMap.blockNumber = mapOrder[i];
               if ((err=MapGet(&checkMap)) != GOOD) {
                  AdrDestroyAddress(checkMap.address);
                  return(err);
               }
               if ((err = AdrGetAddrOffset(checkMap.address, &cmpOffset))
                  != GOOD) {
                  AdrDestroyAddress(checkMap.address);
                  return(err);
               }

               if (gSpaceType != SP_NONE) {
                  cmpSpace  = (checkMap.accessRights&0xff00) >> 8;
                  // cmpAccess = checkMap.accessRights&0x00ff;
                  /*!!none!!*/ //"none" < "ram" < "rom brk" < "rom nobrk"
                  cmpAccess = ((checkMap.accessRights&0x007f)+1) % 4;
               }
               else {
                  cmpSpace = 0;
                  // cmpAccess = checkMap.accessRights;
                  /*!!none!!*/ //"none" < "ram" < "rom brk" < "rom nobrk"
                  cmpAccess = ((checkMap.accessRights%0x007f)+1)%4;
               }
               // add memory type (bit 7) information
               cmpAccess |= (checkMap.accessRights & 0x0080);

               // the comparison order is addr offset, size, access, space
               //
               /* if the new blocks offset is smaller than the current */
               /* map blocks offset then insert the new block before the */
               /* current block */
               if (mapOffset < cmpOffset) {
                  done=found=TRUE;
               } else {
                  if (cmpOffset == mapOffset) {
                  // check block size first,
                  // if same thing, check access rights
                     if (map.blockSize < checkMap.blockSize)
                        done=found=TRUE;
                     else {
                        if (map.blockSize == checkMap.blockSize) {
                           if (mapAccess < cmpAccess)
                              done=found=TRUE;
                           else {
                             if ((mapAccess == cmpAccess) &&
                                   (SpaceOrder(mapSpace,cmpSpace)==GOOD))
                             // everything is the same except space mode,
                             // check the space order
                                done=found=TRUE;
                           }
                        }
                     }
                  }
                  if (!done)
                     i++;
               }
            } else {
               /* the new block belongs in this location */
               done=found=TRUE;
            }
         }
         /* remove the address now that we have the block mapping info */
         if ((err = AdrDestroyAddress(checkMap.address)) != GOOD) return(err);
         
         /* we already know we have a free location, mapblockoverlap
            makes sure of this */
         entry = i;
         if (mapOrder[entry] != DUMMY_MAP_ORDER) {
            /* insert the new entry by shifting all entries up one */
            for (i=mapBlockCount-1; entry < i; i--) {
               mapOrder[i] = mapOrder[i-1];
            }
         }
         /* place the new block number into the list */
         mapOrder[entry] = map.blockNumber;
      } else {
         /* this is the first entry */
         mapOrder[0] = map.blockNumber;
      }
   } else if ((map.enabled == MAP_DISABLE) && (numEntries)) {
      /* remove the block number from the list */
      i=0;
      /* find the index of the block to be removed */
      while ((i < (U16) mapBlockCount) && !found) {
         if (mapOrder[i] != map.blockNumber) i++;
         else found = TRUE;
      }
//!!  if (!found) return(ER_BLOCK_NOT_FOUND);

      if (found && i<(U16)mapBlockCount-1) {
         /* shift all ordered blocks down */
         entry = i;
         for (i=entry; i < (U16)mapBlockCount-1; i++) {
            mapOrder[i] = mapOrder[i+1];
         }
      } 
      /* The very last block can always be set to a dummy value */
      /* if the list was full and one entry is removed then the last entry */
      /* must be made "empty".  if the list was not full then the last */
      /* entry was already "empty" and this value was shifted down one */
      /* place. */
      mapOrder[(U16)mapBlockCount-1] = DUMMY_MAP_ORDER;
   }
   return(GOOD);
}
#define ACCESS_RAM       0
#define ACCESS_ROMBRK    1
#define ACCESS_ROMNOBRK  2
#define ACCESS_NONE      3


RETCODE EXPORT GetMapFromFirmware(VOID)
{
RETCODE err;
MEMORY_MAP_DATA map;
MAP_INFO MapInfo[33];
U8 i;
U8 attrTable[5] = { 1, 0, 0x81, 0x80, 3 };
                /* IR, I,  ER,    E,   G */

   iceGetMap(MapInfo);
   if ((err=AdrCreateAddress(&map.address)) != GOOD)
      return(err);
   for (i=0;;i++) {
     if (MapInfo[i].addr1 == 0xffffffffL) break;
     if ((err=AdrSetAddrOffset(map.address, MapInfo[i].addr1)) != GOOD) {
        AdrDestroyAddress(map.address);
        return(err);
     }
     map.blockSize = MapInfo[i].addr2 - MapInfo[i].addr1 + 1;
     map.accessRights = attrTable[MapInfo[i].attr&7];
     map.enabled = MAP_ENABLE;
     err = MapSet(&map);
   }
   AdrDestroyAddress(map.address);
   return (err);
}


RETCODE EXPORT RelinkEP(VOID) {
S16 status;
U8 retID, i;
RETCODE err;
U32 memFailAddress;
PROBE_TYPE probeType;

   MessageBox(NULL, "Relink EP, Please wait....", "Relink", MB_ICONEXCLAMATION);
   ProcReturnSpecificProcessor(&probeType);
   status = CheckFwStatus();
   switch (status) {
      case DIAGNOSTIC_STATUS :
         DiagnosticFunction(END_DIAG, &memFailAddress,&retID);
         CheckFwStatus();
         DownLoadFirmware((U8 *)"main186.bin", 0x400, 0xff);
         break;
      case COLD_START :
         DownLoadFirmware((U8 *)"main186.bin", 0x400, 0xff);
         break;
      case NORMAL_STATUS :
         status = ICE_WARN_START;
   }
   ReassignProcessorType(probeType);
   if (status != NORMAL_STATUS) {
      Sds2AbiFwUnloadRegisters(TRUE);
      iceSetMap(0L,0L,3); /* Initialize FW MAP table */
      MapClear();
      iceSetMap(0L,0L,3); /* Initialize FW MAP table again */
      for (i=0; i<NUM_LEVELS ;i++)
          Sds2AbiClearTrig(i+1);
      if((err = EnlEventNotify(EVENT_MAP_EDIT))!=GOOD) return(err);
      if((err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE)) != GOOD)
        return(err);
/*      TrcTraceBufferClear(); */
      if((err = EnlEventNotify(EVENT_CPU_HALTED)) != GOOD) return(err);
  }
   MessageBox(NULL, "Relink OK !", "Relink", MB_OK);
   return(GOOD);
}
/******************************** E O F ***********************************/

