/*****************************************************************************
**
**  Name: map.c
**
**  Description: This is the code for simple version of the Map Server
**
**  Status: PRELIMINARY
**
**  $Log:   S:/tbird/arcppc/map/map.c_v  $
** 
**    Rev 1.0   17 Jan 1997 09:38:22   kevin
** Initial revision.
** 
**    Rev 1.1   04 Jun 1996 10:15:54   gene
** remove GetMapFromFirmware() in InitServer()
** 
**    Rev 1.0   03 Jun 1996 11:45:34   gene
** Initial revision.
** 
**    Rev 1.8   03 Jan 1996 16:00:54   kevin
** checked boundary of map blocks in 307 and 328 cases
** 
**    Rev 1.7   20 Nov 1995 11:09:58   kevin
** checked the CPU type before setting map
** 
**    Rev 1.6   17 Nov 1995 11:08:20   kevin
** modified getmapfromfirmware()
** 
**    Rev 1.5   17 Nov 1995 09:20:36   kevin
** added getmapfromfirmware()
** 
**    Rev 1.4   18 Oct 1995 10:07:10   kevin
** NONE setting should be 128KB resolution and on 128KB boundary, and
** on all spaces
** 
**    Rev 1.2   03 Oct 1995 10:49:58   kevin
** fixed a bug while checking a map whether in the area of internal registers
** 
**    Rev 1.1   26 Sep 1995 15:04:00   kevin
** 9/26/95
** 
**    Rev 1.36   29 Jun 1995 14:20:42   marilyn
** Fixed typo.
** 
**    Rev 1.35   29 Jun 1995 14:18:06   marilyn
** Added check for PROC_LC system type for LC support.
** 
**    Rev 1.34   08 May 1995 10:50:10   john
** Merged 1.20.2.2, fixed errors caused by the merge
** 
**    Rev 1.33   01 May 1995 14:20:28   tom
** 10053: Restore Moto map capability.  Much of the logic was removed in order
** to support Intel family.  These changes restore Moto support in a family-
** specific manner by using 2.2G code for mapping Moto blocks.  A better
** approach would be to handle this in a generic manner.
** 
**    Rev 1.32   10 Mar 1995 16:08:46   marilyn
** Merge 1.30.1.0 to the trunk (Kevin's changes).
** 
**    Rev 1.30.1.0   10 Mar 1995 15:59:08   marilyn
** Merge Kevin's changes.
** 
**    Rev 1.31   09 Feb 1995 16:25:34   tom
** 10060: change timeout to 45 seconds so 4M map won't time out.
** 
**    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.2.2   16 Sep 1994 10:00:24   ernie
** Streamlined MapUpdateMembers() and added code to set members back to
** zero if the map command fails in firmware.
** 
**    Rev 1.20.2.1   02 Aug 1994 15:39:34   john
** The code that removes map blocks from the mapOrder array incorrectly
** cleaned up after itself on map blocks >2.  This now works correctly
** but could be excessively slow if there are a large number of map 
** blocks (ie. >>16).
** 
**    Rev 1.20.2.0   17 May 1994 09:28:22   ernie
** Added support for variable map blocks for PP-360
** 
**    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/arcppc/map/map.c_v   1.0   17 Jan 1997 09:38:22   kevin  $
**
**  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 _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 _ABI_DEF_
#include "..\abi68k\abidef.h"
#endif

#ifndef _ABI_FUNC_
RETCODE EXPORT iceGetMap(MAP_INFO *mapData);
#endif

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

#define MAP_TIMEOUT_LIMIT 45   // wait 45 seconds for map cmd to timeout

U32 mapBlockCount;      /* number of HW map blocks */
U32 mapBlockSize;       /* largest size for a HW block */
U32 mapBlockGranularity;   /* minimum size for a HW block */

/* These two flags work in conjunction to let the map server
   know if there is any overlay ram available in the system.
   Originally it was good enough to know if the ovl was present,
   but since PP360 can have ovl present but not available for
   use (i.e. mapranges 0).  There has to be a means for knowing if
   overlay should be re-enabled in this case. */
PRIVATE BOOLEAN mapPresent;
PRIVATE BOOLEAN mapAvailable;

U32 *mapOrder = NULL;


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

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

RETCODE UpdateMapOrder(MEMORY_MAP_DATA map);
RETCODE WriteMapMembers(MEMORY_MAP_DATA map);
RETCODE SetMapPresent(BOOLEAN present);
RETCODE FreeMapEntry(U32 *freeEntry);
RETCODE SpaceOrder(U8 mapSpace, U8 cmpSpace);
RETCODE 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(mapAvailable);
}

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

/****************************************************************************
**
**  InitServer
**
*****************************************************************************/
RETCODE EXPORT InitServer(VOID) {
   static BOOLEAN initAlready=FALSE;
   RETCODE err;
   U16 i;
   MEMORY_MAP_DATA map;

   if (initAlready) {
      /* Free memory from last init operation */
      if (mapBlockCount && mapOrder) {
         TFree((LPSTR)mapOrder);
         mapOrder = NULL;
      }
   }
   
   /* get the number of map blocks provided by the hardware */
   if((err = SdnReadMember(SDN_NUM_MAP_BLOCKS, (U8 FAR *)&mapBlockCount))
      != GOOD) return(err);

   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);

   /* Only set mapPresent when initializing.  Never change it once
      it has been initialized.  Use Get/SetMapPresent() to dynamically
      enable or disable map access.  Use the granularity value to know
      if there is any overlay ram on the epod, since the number of
      map blocks can be overwritten by the host. */
   if (!initAlready) {
      if (mapBlockGranularity) mapPresent = TRUE;
      else mapPresent = FALSE;
   }
   
   initAlready = TRUE;
   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) {
   RETCODE err;
   U32 offset;
   MAP_BLOCK status;
   PROBE_TYPE Processor;

   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);
   
      ProcReturnSpecificProcessor(&Processor);
      if (Processor == M68306_MP) {
         // MP306 occupys the range of 0xFFFFF000~0xFFFFFFFF in SD 
         if ((memMap->accessRights & MAP_SD) && 
               memMap->blockSize-1+offset >= 0xFFFFF000L)
            return(ER_WAIT_BDM_TIMEOUT); // violate system map 
         if ((memMap->accessRights & 3) == 3  // NONE access: 3
               && ((memMap->blockSize % 0x20000l != 0) // 128 KB resolution
                  || (offset % 0x20000l != 0)          // 128 KB boundary
                  || (memMap->accessRights & 0xFF00) != 0x0F00))//all spaces
            return(ER_INPUT_OVERRUN); // not on bank boundary or
      }
      else if (Processor == M68307_MP || Processor == M68328_MP) {
         if ((memMap->accessRights & 3) == 3  // NONE access: 3
               && ((memMap->blockSize % 0x20000l != 0) // 128 KB resolution
                  || (offset % 0x20000l != 0)          // 128 KB boundary
                  || (memMap->accessRights & 0xFF00) != 0x0F00))//all spaces
            return(ER_INPUT_OVERRUN); // not on bank boundary or
      }

      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);
   }
   return(!GOOD); // assertion check
}

/****************************************************************************
**
**  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 there isn't any overlay then it is automatically cleared */
   /* and does not constitute an error */
   if (!GetMapPresent()) return(GOOD);
   
   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) {

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

   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);
}

/****************************************************************************
**
**  WriteMapMembers
**
*****************************************************************************/
RETCODE WriteMapMembers(MEMORY_MAP_DATA map) {
   RETCODE err;
   U32 offset, maxOffset;
   DESCRIPTOR desc;
   BOOLEAN timedOut;
   U8 mapCmd = TRUE;
   U32 zero = 0;

   // 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 */
   if((err = SdnWriteMember(SDN_MAP_ENABLE+map.blockNumber,
      (U8 *)&map.enabled, GOOD)) != GOOD) return(err);

   /* write out the access rights */
   if((err = SdnWriteMember(SDN_MAP_PROTECT+map.blockNumber,
      (U8 *)&map.accessRights, GOOD)) != GOOD) return(err);

   /* set the blocks starting address */
   if ((err = AdrGetAddrOffset(map.address, &offset)) != GOOD) return(err);
   if((err = SdnWriteMember(SDN_MAP_ADDR+map.blockNumber,
      (U8 *)&offset, GOOD)) != GOOD) return(err);

   /* write the block size.  This will cause all entries to be updated */
   if((err = SdnWriteMember(SDN_MAP_LENGTH+map.blockNumber,
      (U8 *)&map.blockSize, GOOD)) != GOOD) return(err);

   if((err = SdnWriteCmdReadResponse(SDN_MAP_COMMAND + map.blockNumber,
      (VOID FAR *)&mapCmd, GOOD, SDN_MAP_RESULTS + map.blockNumber, 
      MAP_TIMEOUT_LIMIT, &timedOut)) != GOOD) {
      /* If command failed, set members back to inactive condition */
      SdnWriteMember(SDN_MAP_ENABLE+map.blockNumber, (U8 *)&zero, GOOD);
      SdnWriteMember(SDN_MAP_PROTECT+map.blockNumber, (U8 *)&zero, GOOD);
      SdnWriteMember(SDN_MAP_LENGTH+map.blockNumber, (U8 *)&zero, GOOD);
      SdnWriteMember(SDN_MAP_ADDR+map.blockNumber, (U8 *)&zero, GOOD);
      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 mapSpace' < cmpSpace'
**
**  Parameters:
**     input:
**        mapSpace: current space
**        cmpSpace: compared space
**
**     output:
**        (reture code): GOOD if correct order
**
*****************************************************************************/
RETCODE SpaceOrder(U8 mapSpace, U8 cmpSpace) {
U8 i;

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

   // Intel case:
   // bit 5: SMM, bit6: User
   if ((mapSpace&0xF0) && (cmpSpace&0xF0)) {
      if (mapSpace < cmpSpace)
         return(GOOD);
      else
         return(!GOOD);
   }

   // Motorola cases:
   // bit 0, 1, 2, 3 ==> SD, SP, UP, UD
   mapSpace &= 0x0F;
   cmpSpace &= 0x0F;
   if (mapSpace && cmpSpace) {
      for (i=0; i<4; i++) {   // compared in reverse order
         if ((mapSpace&1) != (cmpSpace&1)) {
            if (mapSpace&1)
               return(GOOD);    // current map should be in front of its competitor
            else
               return(!GOOD);
         }
         mapSpace >>= 1;
         cmpSpace >>= 1;
      }
      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=(U16) mapBlockCount-1; i>entry; 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);
}

/****************************************************************************
**
**  MapSetMapBlocks
**  MapGetMapBlocks
**
****************************************************************************/
RETCODE EXPORT MapSetMapBlocks(U32 mapBlocks) {
   RETCODE err;
   PROBE_TYPE probeType;
   BOOLEAN timedOut;
   if ((err = SdnReadMember(SDN_PROBE_TYPE, (U8*)&probeType)) != GOOD)
      return(err);
   if (probeType != M68360_TB) return(ER_NOT_SUPPORTED);

   /* check to see if there is any overlay memory on the probe.
      If there isn't don't let the 'mapranges' command work. */
   if (!mapPresent) return(ER_NO_MEMORY_PRESENT);
//kevin   if ((mapBlocks != 0ul) && (mapBlocks != 2ul) && (mapBlocks != 4ul))
//kevin      return(ER_ILLEGAL_MAPBLOCKS);
   if ((err = SdnWriteCmdReadResponse(SDN_NUM_MAP_BLOCKS,(U8*)&mapBlocks, GOOD,
      SDN_GRAN_MAP_BLOCK,0,&timedOut)) != GOOD) return(err);
   return(InitServer());
}

RETCODE EXPORT MapGetMapBlocks(U32 *mapBlocks) {
   RETCODE err;
   if ((err = SdnReadMember(SDN_NUM_MAP_BLOCKS, (U8*)mapBlocks)) != GOOD)
      return(err);
   return(GOOD);
}

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

   iceGetMap(MapInfo);
   if ((err=AdrCreateAddress(&map.address)) != GOOD)
      return(err);
   for (i=0; i<16; i++) {
     if (MapInfo[i].addr1 == 0xffffffffL) continue;
     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]|(MapInfo[i].attr&0xFF80);
     map.enabled = MAP_ENABLE;
     if ((err=MapSet(&map)) != GOOD) {
        map.enabled = MAP_DISABLE;
        MapSet(&map);
     }
   }
   AdrDestroyAddress(map.address);
   return (err);
}

/******************************** E O F ***********************************/

