/***************************************************************************
**
**  Name:  spa.c
**
**  Description:
**       Routines to set up the spa management
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/mt2_186/trace/spa.c_v  $
** 
**    Rev 1.4   09 Jul 1998 15:56:24   Eric
** Fixed bug of range length in Code Coverage.
** 
**    Rev 1.3   21 Jul 1997 14:59:32   Judy
** 
**    Rev 1.2   27 May 1997 15:30:14   Judy
** 
**    Rev 1.0   16 Dec 1996 15:25:54   Judy
** Initial revision.
** 
**    Rev 1.3   15 Nov 1996 16:49:20   Judy
** 
**    Rev 1.2   23 Oct 1996 18:09:34   Judy
** 
**    Rev 1.1   06 Sep 1996 17:30:00   Judy
** 
**    Rev 1.0   23 Aug 1996 17:37:04   Judy
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_186/trace/spa.c_v   1.4   09 Jul 1998 15:56:24   Eric  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

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

#include "stdlib.h"
#ifndef __STRING_H
#include <string.h>
#endif
#ifndef __CTYPE_H
#include "ctype.h"
#endif
#ifndef _BASEWIND_
#include "basewind.h"
#endif
#ifndef _ENLIB_
#include "enlib.h"
#endif
#ifndef _CLISRV_
#include "clisrv.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif
#ifndef _SSHARED_
#include "sshared.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _LOCAL_
#include "local.h"
#endif
/*
#ifndef _EVENT_
#include "event.h"
#endif
*/
#ifndef _PVTASK_
#include "pvtask.h"
#endif

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

#ifndef _CPU_
#include "cpu.h"
#endif

#ifndef _LOADER_
#include "loader.h"
#endif

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

#ifndef  _BKPTEXEC_
#include "bkptexec.h"
#endif

#ifndef _ABI_DEF_
#include "abidef.h"
#endif

#ifndef _SPA_
#include "spa.h"
#endif

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

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


#ifndef NULLPTR
define NULLPTR '\0'
#endif
			/****************************
			 *                          *
			 *    EXTERNAL VARIABLES    *
			 *                          *
			 ****************************/
HANDLE hInst;

U8 spaRangeCnt[2];
static SPA_RANGE spaRangeList[2][SPA_RANGE_NUM];
static SPA_BANK spaBankList[SPA_BANK_NUM];
static BOOLEAN spaStatus=FALSE;
static BOOLEAN bkptStatus=FALSE;
static U32 spaBkptSeg=0xffffffffl, spaBkptOff=0xffffffffl;

			/****************************
			 *                          *
			 *     LOCAL STORAGE        *
			 *                          *
			 ****************************/

static HANDLE cliServerHandle = 0;       /* return address for CLI results */
HANDLE hLib;   // for link SDK


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

RETCODE ConvTextToU32(LPSTR data, U32 *value, BOOLEAN isItAddress);
RETCODE SpaRangeExists(U8 type, LPSTR Name, int *index);
RETCODE SpaRangeCls(U8 type, LPSTR Name);
VOID SpaInitialize(VOID);
RETCODE SpaRangeGetByIdx(U8 type, U8 idx, U8 *index);
RETCODE SpaStartPre(U8 type);
RETCODE SpaStartCCPre(VOID);
RETCODE SpaBankSet(U32 startAddr, U32 endAddr);
RETCODE SpaRangeCreate(U8 type, LPSTR Name, LPSTR startPtr, LPSTR endPtr, int *index);
RETCODE SpaResetCPU(VOID);
RETCODE SpaFree(U8 type);
VOID GetBusData (U32 addr, U32 *addrOut);
			/****************************
			 *                          *
			 *      EXECUTABLE CODE     *
			 *                          *
			 ****************************/

#pragma argsused
int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD cbHeapSize,
    LPSTR lpszCmdLine) {
   hLib=hInstance;
   if (cbHeapSize>0)
      UnlockData(0);
   SpaOpen(SPA_MA, "");
   return(TRUE);
}
/* #ifndef _BORLANDC_*/
/**************************************************************************
**
** WEP {Windows Exit Procedure}
**
** Description: DLL exit procedure to perform cleanup for the DLL before it
**              is unloaded. - not to be used with BC++ compiler.
**
**	Parameters:
**    input:
**       nParam:     Message to indicate whether all of Windows is shutting
**                   down or just the DLL itself.
**
**    output:
**       return a 1 to indicate success
**
**************************************************************************
int FAR PASCAL EXPORT WEP(int nParam) {

   switch(nParam) {
      case WEP_SYSTEM_EXIT:
         break;
      case WEP_FREE_DLL:
         SpaQuit(VOID);
         break;
      default:
         break;
   }
   return(TRUE);
}
#endif */
/**************************************************************************
**
** InitCServer
**
***************************************************************************/
RETCODE EXPORT InitCServer(HANDLE cliHandle, HANDLE dllHandle) {
   CSERVER_NEW_REGISTRATION FAR * msgBufPtr;
   cliServerHandle = cliHandle;
   msgBufPtr = (CSERVER_NEW_REGISTRATION FAR *)
               TMalloc(sizeof(CSERVER_VARIABLE_VALUE));
   if (msgBufPtr == NULL) return(ER_OUT_OF_MEMORY);
   msgBufPtr->stringResourceHandle = dllHandle;
   msgBufPtr->serverNameIndex = 10;
   msgBufPtr->dllNameIndex = 11;
   msgBufPtr->numberOfCommandsIndex = 12;
   msgBufPtr->commandStartIndex = 13;
   SendMessage(cliHandle, CLI_NEW_SVR_REGISTRATION, CLI_NEW_SVR_REGISTRATION,
      (DWORD)msgBufPtr);
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaRangesAdd
** i/p: char *Name = name of the range
**      char *startAddr = segment:offset, start address of the range,
**      char *endAddr = segment:offset,  end address of the range
** 
** Note: To append new range record to spaRangeList
*****************************************************************************/
RETCODE EXPORT SpaRangesAdd(U8 type, LPSTR Name, LPSTR startAddr, LPSTR endAddr) {
   int idx, i;
   RETCODE err;
   i=(type==SPA_CC) ? 1 : 0;
   
   if (SpaRangeExists(type, Name, &idx) == YES)
	 return(ER_FIELD_NAME_DUP);

   if ((err=SpaRangeCreate(type, Name, startAddr, endAddr, &idx))
       != GOOD) return(err);
   spaRangeCnt[i]++;
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaRangesEdit
** i/p: LPSTR Name = name of the range
**      LPSTR startAddr = segment:offset, start address of the range,
**      LPSTR endAddr = segment:offset,  end address of the range
** 
** Note: Setting range to spaRangeList according to the name.
*****************************************************************************/
RETCODE EXPORT SpaRangesEdit(U8 type, LPSTR Name, LPSTR startPtr, LPSTR endPtr) {
   LOOP_VAR idx, i;
   if (SpaRangeExists(type, Name, &idx) != YES)
       return(ER_NOT_FOUND);
   i= (type==SPA_CC) ? 1:0;
   TFree(spaRangeList[i][idx].startPtr);
   if ((spaRangeList[i][idx].startPtr = (LPSTR)TMalloc(11*MAX_SEG_NUM))
       == NULL) return(ER_OUT_OF_MEMORY);
   lstrcpy(spaRangeList[i][idx].startPtr, startPtr);
   TFree(spaRangeList[i][idx].endPtr);
   if ((spaRangeList[i][idx].endPtr = (LPSTR)TMalloc(11*MAX_SEG_NUM))
       == NULL) return(ER_OUT_OF_MEMORY);
   lstrcpy(spaRangeList[i][idx].endPtr, endPtr);
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaRangesGet
** i/p: LPSTR Name = name of the range
**      LPSTR startAddr = segment:offset, start address of the range,
**      LPSTR endAddr = segment:offset,  end address of the range
** Note: To get range data according to the name.
*****************************************************************************/
RETCODE EXPORT SpaRangesGet(U8 type,LPSTR Name, LPSTR startPtr, LPSTR endPtr) {
   LOOP_VAR idx, i;
   i= (type==SPA_CC) ? 1:0;
   if (SpaRangeExists(type, Name, &idx) != YES)
       return(ER_NOT_FOUND);
   *startPtr='\0';
   *endPtr='\0';
   lstrcpy(startPtr, spaRangeList[i][idx].startPtr);
   lstrcpy(endPtr, spaRangeList[i][idx].endPtr);
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaRangesDelete
** i/p: char *Name = name of the range
** 
** Note: To delete range record according to the name
*****************************************************************************/
RETCODE EXPORT SpaRangesDelete(U8 type, LPSTR Name) {
   LOOP_VAR i;
   if (SpaRangeCls(type,Name) == GOOD) {
      i= (type==SPA_CC) ? 1:0;
      spaRangeCnt[i]--;
      return(GOOD);
   }
   return(FALSE);
}
/*****************************************************************************
** 
**    SpaRangesCountGet
** o/p: U8 far *count = number of used range
** 
** Note: To get how many ranges being used.
*****************************************************************************/
RETCODE EXPORT SpaRangesCountGet(U8 type, U8 FAR *count) {
   LOOP_VAR i;
   i= (type==SPA_CC) ? 1:0;
   *count = spaRangeCnt[i];
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaRangesGetByIndex
** i/p: U8 index = no. of the range
**      LPSTR Name
**      LPSTR startAddr
**      LPSTR endAddr
** 
** Note: To get range data according to being used index.
*****************************************************************************/
RETCODE EXPORT SpaRangesGetByIndex(U8 index, U8 type, LPSTR Name,
               LPSTR startAddr, LPSTR endAddr, U8 FAR *item)
{
   U8 idx, i;

   i= (type==SPA_CC) ? 1:0;
   SpaRangeGetByIdx(type, index, &idx);
   *Name='\0';
   lstrcpy(Name, spaRangeList[i][idx].namePtr);
   *startAddr='\0';
   lstrcpy(startAddr, spaRangeList[i][idx].startPtr);
   *endAddr='\0';
   lstrcpy(endAddr, spaRangeList[i][idx].endPtr);
   switch(type){
      case SPA_TA:
           *item = (spaRangeList[i][idx].item & 0x30) >> 4;
           break;
      case SPA_CC:
           *item = (spaRangeList[i][idx].item & 0xc0) >> 6;
           break;
      default:  /* MA */
           *item = spaRangeList[i][idx].item & 0x0f;
           break;
   }
   *item=(*item < 4) ? *item : DEF_ITEM;
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaSaveDataGet
** o/p: U8 index = number of used range
**      SPA_RANGE_TEMP *data= data
** 
** Note: To get ranges data.
*****************************************************************************/
RETCODE EXPORT SpaSaveDataGet(U8 type, U8 index, SPA_RANGE_TEMP *data) {
   U8 idx,i;
   i= (type==SPA_CC) ? 1:0;
   SpaRangeGetByIdx(type, index, &idx);
   data->namePtr=spaRangeList[i][idx].namePtr;
   data->startPtr=spaRangeList[i][idx].startPtr;
   data->endPtr=spaRangeList[i][idx].endPtr;
   data->item=spaRangeList[i][idx].item;
   lstrcpy(data->buffer, spaRangeList[i][idx].namePtr);
   lstrcpy(data->buffer+SPA_RANGE_NAME_NUM, spaRangeList[i][idx].startPtr);
   lstrcpy(data->buffer+SPA_RANGE_NAME_NUM+11*MAX_SEG_NUM, spaRangeList[i][idx].endPtr);
   return(GOOD);
}


/*****************************************************************************
** 
**    SpaRangesActionSet
** i/p: LPSTR name
**      SPA_RUN_MODE type
**      SPA_RANGE_ID id
** 
** Note: To set spaRangeList[].item
*****************************************************************************/
RETCODE EXPORT SpaRangesActionSet(LPSTR Name, U8 type, SPA_RANGE_ID id) {
   U8 i,k;
   LOOP_VAR idx;
   k= (type==SPA_CC) ? 1:0;
   if (SpaRangeExists(type, Name, &idx) != YES)
       return(ER_NOT_FOUND);
   switch(type){
      case SPA_TA:
           spaRangeList[k][idx].item &= 0xcf;
           i=id << 4;
           break;
      case SPA_CC:
           spaRangeList[k][idx].item &= 0x3f;
           i=id << 6;
           break;
      default:  /* MA */
           spaRangeList[k][idx].item &= 0xf0;
           i=id;
           break;
   }
   spaRangeList[k][idx].item |= i;
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaRangesActionGet
** i/p: LPSTR name
**      SPA_RUN_MODE type
**      SPA_RANGE_ID id
** 
** Note: To get spaRangeList[].name according to id
*****************************************************************************/
RETCODE EXPORT SpaRangesActionGet(U8 type, SPA_RANGE_ID id, LPSTR name) {
   LOOP_VAR i, j, k;
   *name=NULLPTR;
   k= (type==SPA_CC) ? 1:0;
   for (i=0; i< SPA_RANGE_NUM; i++) {
       if (spaRangeList[k][i].item != 0xff) {
          j=(type == SPA_MA) ? spaRangeList[k][i].item & 0x0f :
             (spaRangeList[k][i].item & 0x30) >> 4;
          if (j==id) {
             lstrcpy(name, spaRangeList[k][i].namePtr);
             return(GOOD);
          }
       }
   }
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaRangesActionClear
** i/p: SPA_RUN_MODE type
**      LPSTR name
** 
** Note: To clear spaRangeList[].item according to type and name
*****************************************************************************/
RETCODE EXPORT SpaRangesActionClear(LPSTR name, U8 type) {
   LOOP_VAR idx, k;
   k= (type==SPA_CC) ? 1:0;
   if (SpaRangeExists(type, name, &idx) != YES)
       return(ER_NOT_FOUND);
   spaRangeList[k][idx].item=(type == SPA_MA) ? spaRangeList[k][idx].item | 0x0f :
       spaRangeList[k][idx].item | 0xf0;
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaMAGet
** i/o: U32 *stamp : total timestamp
**      SPA_MA_INFO *data[4]: count and time data
**      BOOLEAN *flag = 0, running
**                      1, halt
** 
** Note: To get module analysis information.
*****************************************************************************/
RETCODE EXPORT SpaMAGet(U32 *stamp, SPA_MA_INFO *data, BOOLEAN *flag) {
   RETCODE err;
   err=Sds2AbiSpaGetMAInfo(stamp, data, flag);
   spaStatus=*flag;
   if (spaStatus == TRUE) {
      if((err = Sds2AbiFwUnloadRegisters(TRUE)) != GOOD) return(err);
   }
   return(err);
}
/*****************************************************************************
** 
**    SpaTAGet
** i/o: U32 *stamp[3] : total, longest, shortest time
**      U16 *data[9]: count data
**      BOOLEAN *flag = 0, running
**                      1, halt
** 
** Note: To get time analysis information.
*****************************************************************************/
RETCODE EXPORT SpaTAGet(U32 *stamp, U16 *data, BOOLEAN *flag) {
   RETCODE err;
   err=Sds2AbiSpaGetTAInfo(stamp, data, flag);
   spaStatus=*flag;
   if (spaStatus == TRUE) {
      if((err = Sds2AbiFwUnloadRegisters(TRUE)) != GOOD) return(err);
   }
   return(err);
}
/*****************************************************************************
** 
**    SpaCCGet
** i/o:
**      LPSTR startAddr
**      LPSTR endAddr
**      LPSTR ptr
**      BOOLEAN *flag = 0, running
**                      1, halt
** 
** Note: To get code coverage information.
*****************************************************************************/
RETCODE EXPORT SpaCCGet(LPSTR startPtr, LPSTR endPtr, LPSTR ptr, BOOLEAN *flag) {
   U32 startAddr, endAddr;
   RETCODE err;
   ConvTextToU32(startPtr, &startAddr, TRUE);
   ConvTextToU32(endPtr, &endAddr, TRUE);
   err=Sds2AbiSpaGetCCInfo(startAddr, endAddr, ptr, flag);
   spaStatus=*flag;
   if (spaStatus == TRUE) {
      if((err = Sds2AbiFwUnloadRegisters(TRUE)) != GOOD) return(err);
   }
   return(err);
}
/*****************************************************************************
** 
**    SpaStart
** i/o: SPA_RUN_MODE type
** 
** Note: RUN
*****************************************************************************/
RETCODE EXPORT SpaStart(U8 type) {
   U32 addr;
   RETCODE err;
   spaStatus=TRUE;
   SpaResetCPU();

   if((err=Sds2AbiSpaClearRange(type))!=GOOD) return err;

   if (spaBkptSeg!=0xFFFFFFFF && spaBkptOff != 0xFFFFFFFF) {
      addr = spaBkptSeg;
      addr <<=16;
      addr |= spaBkptOff;
      bkptStatus=TRUE;
   } else
      bkptStatus=FALSE;

   if((err=Sds2AbiSpaSetBkpt(bkptStatus, addr))!=GOOD) return err;
   if (type == SPA_CC) {
      if((err=SpaStartCCPre())!=GOOD) return err;
   }
   else {
      if((err=SpaStartPre(type))!=GOOD) return err;
   }
   return(Sds2AbiSpaGo(type+5));
}
/*****************************************************************************
** 
**    SpaStop
** i/o: SPA_RUN_MODE type
** 
** Note: RUN
*****************************************************************************/
#pragma argsused
RETCODE EXPORT SpaStop(U8 type) {
//   BxHaltEmulation();
   RETCODE err;
   iceAbort();
   spaStatus=FALSE;
   if((err = Sds2AbiFwUnloadRegisters(TRUE)) != GOOD) return(err);
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaCreate
** 
** Note: To create spaRangeList and spaBankList.
*****************************************************************************/
RETCODE EXPORT SpaCreate(VOID) {
   return(Sds2AbiSpaOpen());
}
/*****************************************************************************
** 
**    SpaOpen
** 
** Note: To create spaRangeList and spaBankList.
*****************************************************************************/
RETCODE EXPORT SpaOpen(U8 type, LPSTR fileName) {
   int hFile;
   int index, i, k;
   RETCODE err;
   SPA_RANGE_TEMP FAR *temp;
   char aa=' ';


   if (fileName && (lstrlen(fileName) > 0)) {
      if((hFile = _lopen(fileName,OF_READ)) == -1) return(ER_CANT_OPEN_FILE);
      SpaFree(type);
      k= (type==SPA_CC) ? 1:0;
      if(_lread(hFile,&aa,1) != 1)
         return(ER_READING_FILE);
      spaRangeCnt[k]=(U8)aa;
      if((temp = (SPA_RANGE_TEMP FAR *)TMalloc(sizeof(SPA_RANGE_TEMP))) == NULL)
         return(ER_OUT_OF_MEMORY);
      for (i=0;i<spaRangeCnt[k];i++) {
          if(_lread(hFile,(LPSTR)temp, sizeof(SPA_RANGE_TEMP)) !=
             sizeof(SPA_RANGE_TEMP))
             return(ER_READING_FILE);
          if((err=SpaRangeCreate(type, (LPSTR)temp->buffer,
              (LPSTR)(temp->buffer+SPA_RANGE_NAME_NUM),
	      (LPSTR)(temp->buffer+SPA_RANGE_NAME_NUM+11*MAX_SEG_NUM), &index))!=GOOD)
              return(err);
          spaRangeList[k][index].item=temp->item;
      }
      TFree((LPSTR)temp);
      _lclose(hFile);
   }
   else {
      SpaInitialize();
   }
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaClose
** 
** Note: The function must be executed when  spa window exits. In order to
**       change EP machine status.
*****************************************************************************/
RETCODE EXPORT SpaClose(VOID) {
   RETCODE err;
   if((err=Sds2AbiSpaClose())!=GOOD) return(err);
   if((err = Sds2AbiFwUnloadRegisters(TRUE)) != GOOD) return(err);
   /*
   EnlEventNotify(EVENT_HL_BKPTEXEC_EMUL_STARTED);
   EnlEventNotify(EVENT_HL_BKPTEXEC_EMUL_STEPPING);
   EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE);
   EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC1_RANGE);
   EnlEventNotify(EVENT_BKPT_EDIT);
   EnlEventNotify(EVENT_CPU_PC_EDIT);
   EnlEventNotify(EVENT_DASM_HALTED);
   EnlEventNotify(EVENT_DASM_SYM_CHANGED);              */
   if( (err=EnlEventNotify(EVENT_BKPT_HALTED)) != GOOD )
       ErrDisplayError(err, CHECK_MODE);
   return(err);
}
/*****************************************************************************
** 
**    SpaStatus
** 
** Note: return spa status: TRUE : running
**                          FALSE : halt
*****************************************************************************/
RETCODE EXPORT SpaStatus(VOID) {
   return(spaStatus);
}
/*****************************************************************************
** 
**    SpaSetBkpt
** 
*****************************************************************************/
RETCODE EXPORT SpaSetBkpt(U32 segStr,U32 offStr) {
   spaBkptSeg=segStr;
   spaBkptOff=offStr;
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaGetBkpt
** 
*****************************************************************************/
RETCODE EXPORT SpaGetBkpt(U32 *segStr, U32 *offStr) {
   *segStr=spaBkptSeg;
   *offStr=spaBkptOff;
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaQuit
** 
** Note: To quit spaRangeList and spaBankList.
*****************************************************************************/
RETCODE EXPORT SpaQuit(VOID) {

 SpaFree(SPA_MA);
 SpaFree(SPA_CC);
 return(GOOD);
}

/*************************** CLI FUNCTIONS ******************************/
/****************************** LOCAL FUNCTIONS *****************************/

/*****************************************************************************
** 
**    SpaRangeExists
** 
**    Description:
**       Tells whether an range name has been defined
**
**    Parameters:
**       input:
**          Name:  name of spa range
**       output:
**          index:      index into table of spaRangeList (if TRUE returned)
*****************************************************************************/
RETCODE SpaRangeExists(U8 type, LPSTR Name, int *index) {
   U8 i;
   i= (type==SPA_CC) ? 1:0;
   for ((*index)=0; (*index)<SPA_RANGE_NUM; (*index)++) {
       if (spaRangeList[i][*index].namePtr != NULLPTR) {
          if (lstrcmp(Name, spaRangeList[i][*index].namePtr)==0)
             return(YES);
       }
   }
   return(NO);
}
/*****************************************************************************
** 
**    SpaRangeCls
**
**    Description:
**       To clear range record.
**
**    Parameters:
**       input:
**          Name:  name of spa range
*****************************************************************************/
RETCODE SpaRangeCls(U8 type, LPSTR Name) {
   LOOP_VAR idx,i;
   i= (type==SPA_CC) ? 1:0;
   if (SpaRangeExists(type, Name, &idx)==YES) {
      TFree(spaRangeList[i][idx].namePtr);
      spaRangeList[i][idx].namePtr=NULLPTR;
      TFree(spaRangeList[i][idx].startPtr);
      spaRangeList[i][idx].startPtr=NULLPTR;
      TFree(spaRangeList[i][idx].endPtr);
      spaRangeList[i][idx].endPtr=NULLPTR;
      spaRangeList[i][idx].item=DEF_ITEM;
      return(GOOD);
   }
   return(NO);
}
/*****************************************************************************
** 
**    SpaInitialize
** 
**    Description:
**       Set spa to default configuration.
**
**    Parameters:
**       input:
**          spa:      far pointer to spa structure to initialize
**       output:
**          none
*****************************************************************************/
VOID SpaInitialize(VOID) {
   WORD i,j;
   for (j=0; j<2; j++) {
       for (i=0; i<SPA_RANGE_NUM;i++) {
           spaRangeList[j][i].namePtr=NULLPTR;
           spaRangeList[j][i].startPtr=NULLPTR;
           spaRangeList[j][i].endPtr=NULLPTR;
           spaRangeList[j][i].item=DEF_ITEM;
       }
    spaRangeCnt[j]=0;
   }
   for (i=0; i< SPA_BANK_NUM; i++) {
       spaBankList[i].startAddr=0;
       spaBankList[i].cnt=0;
   }
}


/**************************************************************************
**
** SpaRangeGetByIdx
** i/o: U8 idx: index of being used
**      U8 index: index of spaRangeList
**
** Note: To map idx of being used to index of the spaRangeList
***************************************************************************/
RETCODE SpaRangeGetByIdx(U8 type, U8 idx, U8 *index) {
   U8 i, j, k;
   k= (type==SPA_CC) ? 1:0;
   for (i=j=0; i<SPA_RANGE_NUM; i++) {
       if (spaRangeList[k][i].namePtr != NULLPTR) {
           if (j==idx) {
              *index=i;
              return(GOOD);
           }
        j++;
       }
   }
   return(GOOD);
}
/*****************************************************************************
** 
**    SpaStartCCPre
** 
** Note: To clear old ranges and set new ranges befor run code coverage
*****************************************************************************/
RETCODE SpaStartCCPre(VOID) {
   LOOP_VAR i, k;
   U32 startAddr, endAddr, addr;
   RETCODE err;
   char item;

   k= 1;
   for (i=0; i< SPA_BANK_NUM; i++) {
       spaBankList[i].startAddr=0;
       spaBankList[i].cnt=0;
   }
   for (i=0; i< SPA_RANGE_NUM; i++) {
       item=(spaRangeList[k][i].item & 0xc0) >> 6;
       if (spaRangeList[k][i].namePtr != NULLPTR && item == 1) {
          ConvTextToU32(spaRangeList[k][i].startPtr, &addr, TRUE);
          GetBusData(addr, &startAddr);
          ConvTextToU32(spaRangeList[k][i].endPtr, &addr, TRUE);
          GetBusData(addr, &endAddr);
          if (SpaBankSet(startAddr, endAddr) != GOOD)
             return(ERR_TOO_MANY_DATA_ITEMS);
       }
   }
   for (i=0; i< SPA_BANK_NUM; i++) {
       if (spaBankList[i].cnt != 0) {
          //if((err=Sds2AbiSpaSetRange(SPA_CC, 0, spaBankList[i].startAddr
          //  , spaBankList[i].startAddr+0xffff)) != GOOD) //Eric 7/9/98 for bug #307
          if((err=Sds2AbiSpaSetRange(SPA_CC, i, spaBankList[i].startAddr
            , spaBankList[i].startAddr+0xffff)) != GOOD)
              return(err);
       }
   }
 return(GOOD);
}
/*****************************************************************************
** 
**    SpaStartPre
** i/o: SPA_RUN_MODE type
** 
** Note: To clear old ranges and set new ranges before run MA/TA
*****************************************************************************/
RETCODE SpaStartPre(U8 type) {
   LOOP_VAR i, chk, item, k;
   U32 startAddr, endAddr, addr;
   RETCODE err;
   k= (type==SPA_CC) ? 1 : 0;
   chk = (type == SPA_MA) ? 0x0f : 0x30;
   for (i=0; i< SPA_RANGE_NUM; i++) {
       if ((item=spaRangeList[k][i].item & chk) != chk) {
          item >>= (type * 4);
          ConvTextToU32(spaRangeList[k][i].startPtr, &addr, TRUE);
          GetBusData(addr, &startAddr);
          ConvTextToU32(spaRangeList[k][i].endPtr, &addr, TRUE);
          GetBusData(addr, &endAddr);
          if((err=Sds2AbiSpaSetRange(type, item, startAddr, endAddr)) != GOOD)
            return(err);
       }
   }
 return(GOOD);
}
/*****************************************************************************
** 
**    SpaBankSet
** 
*****************************************************************************/
RETCODE SpaBankSet(U32 start, U32 end) {
   U32 BStartAddr;
   U32 BEndAddr;
   U8 i;
   BStartAddr=(start & 0xffff0000L);
   for (i=0; i< SPA_RANGE_NUM; i++) {
       if (spaBankList[i].cnt==0) {
          spaBankList[i].startAddr=BStartAddr;
          BStartAddr += 0x10000L;
          spaBankList[i].cnt++;
       } else {
           if (spaBankList[i].startAddr <= BStartAddr &&
               BStartAddr <= (spaBankList[i].startAddr | 0xffff)) {
              BStartAddr += 0x10000L;
              spaBankList[i].cnt++;
           }
       }
       BEndAddr=spaBankList[i].startAddr | 0xffff;
       if (BEndAddr >= end)
          return(GOOD);
   }
 return(FALSE);
}
/*****************************************************************************
** 
**    SpaRangeCreate
** 
**    Description:
**       Adds a new spa range to the spaRangeList, if there is room.
**
**    Parameters:
**       input:
**          Name:  name of spa range
**       output:
**          index:      index into table of spaRangeList (if no error returned)
*****************************************************************************/
RETCODE SpaRangeCreate(U8 type, LPSTR Name, LPSTR startPtr, LPSTR endPtr, int *index)
{
   int idx,i;
   i= (type==SPA_CC) ? 1:0;
   for(idx=0; idx<SPA_RANGE_NUM; idx++) {
      if(spaRangeList[i][idx].namePtr == NULLPTR) {
         if ((spaRangeList[i][idx].namePtr = (LPSTR)TMalloc(SPA_RANGE_NAME_NUM))
            == NULL) return(ER_OUT_OF_MEMORY);
         *spaRangeList[i][idx].namePtr=NULLPTR;
         lstrcpy(spaRangeList[i][idx].namePtr, Name);
         if ((spaRangeList[i][idx].startPtr = (LPSTR)TMalloc(11*MAX_SEG_NUM))
            == NULL) return(ER_OUT_OF_MEMORY);
         *spaRangeList[i][idx].startPtr=NULLPTR;
         lstrcpy(spaRangeList[i][idx].startPtr, startPtr);
	 if ((spaRangeList[i][idx].endPtr = (LPSTR)TMalloc(11*MAX_SEG_NUM))
            == NULL) return(ER_OUT_OF_MEMORY);
         *spaRangeList[i][idx].endPtr=NULLPTR;
         lstrcpy(spaRangeList[i][idx].endPtr, endPtr);
         *index=idx;
	 return(GOOD);
      }
   }
 return(ERR_TOO_MANY_DATA_ITEMS);
}

/*****************************************************************************
** 
**    ConvTextToU32
** 
**    Description:
**       Converts a string to a 32 bit value.  THe string is an "address"
**    Which means we send the string to the address routine and let it parse
**    literal numbers, symbols and symbols with offsets.
**
**    Parameters:
**       input:
**          data:    string to be converted
**       output:
**          value:   translated value
*****************************************************************************/
RETCODE ConvTextToU32(LPSTR data, U32 *value, BOOLEAN isItAddress) {
   DESCRIPTOR addrDesc;
   RETCODE err;
   if( isItAddress ) {
      /* Addr conv text to address routine eats up the string - so
	 make a copy to send since calling routines usually wants
	 a good copy of the string to save around.
       */
      S8 tempString[256];
      lstrcpy(tempString,data);   
      if((err=AdrCreateAddress(&addrDesc))!=GOOD) return(err);
      if((err=AdrSetAddrSymbolUsage(addrDesc,TRUE))!=GOOD) return(err);
      if((err=AdrConvTextToAddress(addrDesc,tempString))!=GOOD) return(err);

      /* Modified by Dennis Lamb, May 23, 1994.                        */
      /* Changed this code to support 386 stuff. Call used to be:      */
	  /* if((err=AdrGetAddrOffset(addrDesc,value))!=GOOD) return(err); */
      if((err=AdrGetAddrPhysicalOffset(addrDesc,value))!=GOOD) return(err);
 
      if((err=AdrDestroyAddress(addrDesc))!=GOOD) return(err);
   }
   else {
      S8 *endPtr;
      *value = strtoul(data, &endPtr, 0);
      if (*endPtr != 0) return(ER_CANT_CONV_TEXT);
   }
   return(GOOD);
}

/*****************************************************************************
** 
**    SpaResetCPU
** 
**    Description:
**
**    Parameters:
**       input:
**       output:
*****************************************************************************/
RETCODE SpaResetCPU(VOID) {
   DESCRIPTOR addrDesc;
   U32 regValue,stackSize;
   ADDR_SEGSEL_TYPE type;
   RETCODE err=0;
   U32 segValue=0L;


   if((err=CpuResetCPUOnly()) != GOOD) return err;

   if((err=LdrGetStartPC(&addrDesc)) != GOOD) return err;
   if((err=AdrGetAddrSegmentSelector (addrDesc, &type, (U16 FAR *)&segValue))
           != GOOD) return(err);
   if((err=Sds2AbiSetReg(0x0A,segValue))!=GOOD) return(err);
   if ((err = AdrGetAddrOffset(addrDesc, (U32 FAR *)&regValue)) != GOOD)
      return(err);
   if((err=Sds2AbiSetReg(0x00,regValue))!=GOOD) return(err);
   AdrDestroyAddress(addrDesc);

   if((err=LdrGetStackInfo(&addrDesc, &stackSize)) != GOOD) return err;
   if((err=AdrGetAddrSegmentSelector (addrDesc, &type, (U16 FAR *)&segValue))
           != GOOD) return(err);
   if((err=Sds2AbiSetReg(0x0F,segValue))!=GOOD) return(err);
   if ((err = AdrGetAddrOffset(addrDesc, (U32 FAR *)&regValue)) != GOOD)
      return(err);
   if((err=Sds2AbiSetReg(0x01,regValue))!=GOOD) return(err);
   AdrDestroyAddress(addrDesc);
   return(GOOD);
}

VOID GetBusData (U32 addrIn, U32 *addrOut) {
   PROBE_TYPE specificProcessor;

   *addrOut=addrIn;
   ProcReturnSpecificProcessor(&specificProcessor);
   switch (specificProcessor) {
      case I80C186_MP:
      case I80C186XL_MP:
      case I80C186EA_MP:
      case I80C186EB_MP:
      case I80C186EC_MP:
        if ( (addrIn % 2)==1 )
           *addrOut=addrIn-1;
        break;
      default:
        break;
   }
}

/*****************************************************************************
** 
**    SpaFree
** 
** Note: To quit spaRangeList and spaBankList.
*****************************************************************************/
RETCODE SpaFree(U8 type) {
   LOOP_VAR i, k;

   k= (type==SPA_CC) ? 1:0;
   for (i=0; i< SPA_RANGE_NUM; i++) {
       if (spaRangeList[k][i].namePtr != NULLPTR) {
          TFree(spaRangeList[k][i].namePtr);
          spaRangeList[k][i].namePtr = NULLPTR;
          TFree(spaRangeList[k][i].startPtr);
          spaRangeList[k][i].startPtr = NULLPTR;
          TFree(spaRangeList[k][i].endPtr);
          spaRangeList[k][i].endPtr = NULLPTR;
          spaRangeList[k][i].item=DEF_ITEM;
       }
   }
 return(GOOD);
}
/******************************** E O F ***********************************/
