/****************************************************************************
**
**  Name:  cpu.c
**
**  Description:
**     Routines to access CPU registers and signals.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/arcppc/cpu/cpu.c_v  $
** 
**    Rev 1.14   08 Apr 1998 10:55:06   hera
** for ppc821
** 
**    Rev 1.13   13 Jan 1998 14:04:54   Winky
** Check "Run Access" while setting breakpoints.
** 
**    Rev 1.12   08 Jan 1998 15:47:34   Winky
** Check "Run Access" before CpuGetRegister.
** 
**    Rev 1.11   09 Dec 1997 11:37:38   kevin
** Fixed the same bug of Rev 1.10
** 
**    Rev 1.10   05 Dec 1997 16:11:28   kevin
** Don't report error no matter whether the contents of SRR0, LR, and GPR01 are
** odd or not.
** 
**    Rev 1.9   03 Dec 1997 11:05:38   kevin
** Register command for showing all stock registers
** 
**    Rev 1.8   19 Sep 1997 16:33:00   kevin
** added IMMR evnet
** 
**    Rev 1.7   19 Aug 1997 15:55:40   cjchen
** 
**    Rev 1.6   28 Jul 1997 10:01:50   cjchen
** 
**    Rev 1.5   18 Jul 1997 17:55:04   cjchen
** 
**    Rev 1.4   15 Jul 1997 09:59:26   cjchen
** 
**    Rev 1.3   11 Mar 1997 18:01:16   kevin
** Fixed a bug of getstockregnames()
** 
**    Rev 1.2   11 Mar 1997 09:33:34   kevin
** temp version for PowerPC
** 
**    Rev 1.1   11 Feb 1997 11:36:32   kevin
** PowerPC
** 
**    Rev 1.0   17 Jan 1997 09:12:04   kevin
** Initial revision.
**
**  $Header:   S:/tbird/arcppc/cpu/cpu.c_v   1.14   08 Apr 1998 10:55:06   hera  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

		       /****************************
                            *                          *
                            *       INCLUDE FILES      *
                            *                          *
                            ****************************/
#include <string.h>
#include <ctype.h>

#ifndef _BASEWIND_
#include "basewind.h"   /* basetype */
#endif

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

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

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

#ifndef _CLIULIB_
#include "cliulib.h"
#endif

#ifndef _CPU_
#include "cpu.h"        /* CPU Server */
#endif

#ifndef _CPUCLI_
#include "cpucli.h"     /* CPU Server cli and Internal data structures */
#endif

#ifndef _CPUERR_
#include "cpuerr.h"
#endif

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

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

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

#ifndef _PROC_
#include "proc.h"
#endif

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

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

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

#ifndef SHARED_DATA_MEMBERS
#include "members.h"
#endif

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

/*
*** IMPORTANT NOTES: The order of registers in the cpuRegTable and signalTable
*** are designed to be matched exactly with the order of their enumurate types
*** (REG_NAME and SIG_NAME - defined in the 68030.h file.) Therefore, any ordering
*** change of these tables must ensure a corresponding change of its enum types
*** order. - MAX_REGISTERS and MAX_SIGNALS defined in CPUCLI.H
 */

/* static data */
REGISTER_ENTRY *regTable;   /* registers */
SIGNAL_ENTRY *signalTable;  /* signals */
STOCK_REGISTER* pStockReg;

REGNAME *stockRegName; // To store all stock register names
U16 nStockRegisters;

U16 nRegisters;             /* number of registers */
U16 nSignals;               /* number of signales */
U16 bitReady = 1; //!! for Ready signal

#define MAX_PAIRS_SUPPORTED 32      /* 10 pair should be enough */
U16 nRegPairs=0;                    /* number of assigned register pairs */
REGISTER_PAIR_ENTRY regPairTable[MAX_PAIRS_SUPPORTED]; 

REG_ID framePtrReg = 1;             /* default frame pointer is index 2 */
		    
DESCRIPTOR emulStateDesc = NULL, resetDesc = NULL;
DESCRIPTOR emuHaltedDesc = NULL;
DESCRIPTOR pcRegDesc = NULL, spRegDesc = NULL, fpRegDesc = NULL;

/* CPU Default Notified Events */
BOOLEAN alreadyTerminated = FALSE;

/*                        AS      DS      RESET   HALT    BERR    BRQ     INT     DELAY */
U16 sigXlatTable603e[7]= {0x0040, 0x0080, 0x0400, 0x0800, 0x1000, 0x2000, 0x0001};
U16 sigXlatTable860[7] = {0x0040, 0x0080, 0x0400, 0x0800, 0x1000, 0x2000, 0x0001};
					/****************************
					*                           *
					*    EXTERNAL VARIABLES     *
					*                           *
					****************************/
/* Flag to turn off event propagation when call reset from CLI */
extern HANDLE  hLib;

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

RETCODE PRIVATE GetRegAddr(REG_ID regId, DESCRIPTOR FAR *desc);
RETCODE PRIVATE SetRegAddr(REG_ID regId, DESCRIPTOR desc);

/* Internal callback routine */
VOID EXPORT CpuEmulHaltedCallback(U32 event);

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

/* See CPUCLI.C for Cpu Server's CLI commands */
/*****************************************************************************
**
**    InitCpuServer
**
*****************************************************************************/
static BOOLEAN initCpuServer = FALSE;
RETCODE EXPORT InitCpuServer(VOID) {
   RETCODE err = GOOD;
   U16 i;
//   U8  Disable = FALSE;
   FARPROC lpCallback;
//   PROBE_TYPE specificProcessor;

   if( initCpuServer ) return(GOOD);
   initCpuServer = TRUE;
//   if ((err = ProcReturnSpecificProcessor(&specificProcessor)) != GOOD)
//      return(err);

   if ((err = SdnRegister(SDN_EMULATION_STATE, NULLPTR,&emulStateDesc))!=GOOD)
      return(err) ;
   if ((err = SdnRegister(SDN_RESET_CPU, NULLPTR, &resetDesc)) != GOOD)
      return(err) ;

   /* read in processor-specific configuration, and build register table
      and signal table */
   if ((err = BuildTables(FALSE)) != GOOD) return(err);

   iceSetReady(1);
   /* Initialize all signal descriptors */
   for (i = 0; i < nSignals; i++) {
      if ((err = SdnRegister(SDN_SIG00+i, NULLPTR, &signalTable[i].sdDesc))
	    != GOOD) return(err);
   }
   
   lpCallback = MakeProcInstance((FARPROC)CpuEmulHaltedCallback, hLib);
   if ((err = EnlRegister((U32)EVENT_BKPT_HALTED,
      (EVCALLBACK)lpCallback, (DESCRIPTOR FAR *)&emuHaltedDesc)) != GOOD)
      return(err);
   GetStockRegNames(&nStockRegisters);

   return(GOOD);
}

/*****************************************************************************
**
**    TerminateServer
**
*****************************************************************************/
RETCODE EXPORT TerminateServer(VOID) {
   RETCODE err = GOOD;
   U16 i;

   /* Check global flag to avoid terminatte being called more than one */
   if (alreadyTerminated)
      return(GOOD);
   
   /* do first, in case of error... don't try again */
   alreadyTerminated = TRUE;

   /* Unregister Event -- If can not unregister, error out */
   if (emuHaltedDesc && ((err = EnlUnRegister(emuHaltedDesc)) != GOOD))
      return(err);

   /* Unregister descriptors */
   if (emulStateDesc && ((err = SdUnRegister(emulStateDesc)) != GOOD))
      return(err);
   if (resetDesc && ((err = SdUnRegister(resetDesc)) != GOOD)) return(err);

   for (i = 0; i<nSignals; i++) {
      /* Unregister its descriptor */
      if (signalTable[i].sdDesc &&
	 ((err = SdUnRegister((DESCRIPTOR) signalTable[i].sdDesc)) != GOOD))
	 return(err);
   }
   TFree(regTable);
   TFree(stockRegName);

   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetNumRegs
**
*****************************************************************************/
RETCODE EXPORT CpuGetNumRegs(U16 FAR *numRegs) {
   *numRegs = nRegisters;
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetRegister
**
*****************************************************************************/
RETCODE EXPORT CpuGetRegister(REG_ID regId, U32 FAR *regValue) {
   REG_ID curId=regId;
   RETCODE err;
   BOOLEAN runAccess;

//   U32 curVal=0L;

   if (regId >= (nStockRegisters+nRegPairs)) return(ER_INVALID_REGID);
//   if( regId >= nStockRegisters) {
//      if((err=GetRegFromHost(regTable[regPairTable[(regId-nStockRegisters)][0]].fwRegOrder,
//                             &curVal))!=GOOD) return(err);
//      curId = regPairTable[(regId-nStockRegisters)][1];
//      curVal <<= 16; // !!32 bits
//   }

   /* Winky 1/8/98 */
   if ((err = BkGetRunAccess(&runAccess)) != GOOD) return(err);

   /* emulation must be halted to set registers */
   if (!runAccess)
      if((err = BkProcessorMustBeHaltedAbsolute())!=GOOD) return(err);

   if((err=GetRegFromHost(regTable[curId].fwRegOrder, regValue))!=GOOD)
      return(err);
   // if handling register pairs...
//   if (regId >= nStockRegisters) *regValue = curVal | (*regValue & 0xffffL);//!!32bit
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetStockRegister
**
*****************************************************************************/
RETCODE EXPORT CpuGetStockRegister(REG_ID regId, U32 FAR *regValue) {
   REG_ID curId=regId;
   RETCODE err;

   if (regId >= (nStockRegisters+nRegPairs)) return(ER_INVALID_REGID);
   if((err=GetRegFromHost(pStockReg[curId].order, regValue))!=GOOD)
      return(err);
   return(GOOD);
}
/*****************************************************************************
**
**    CpuSetRegister
**
*****************************************************************************/
RETCODE EXPORT CpuSetRegister(REG_ID regId, U32 regValue) {
   RETCODE err;
   REG_ID curReg;
   PROC_CPU cpu;
   U8 width;
   U32 sim;

   if (regId >= (nStockRegisters+nRegPairs)) return(ER_INVALID_REGID);
   if((err=CpuGetRegisterWidth(regId, &width))!=GOOD) return(err);
   if( width < 32) {
      if (regValue >= (1L << width)) return(ER_REG_OUT_OF_RANGE);
   }
   /* emulation must be halted to set registers */
   if((err = BkProcessorMustBeHaltedAbsolute())!=GOOD) return(err);
 
   if ((err = ProcReturnCpu(&cpu)) != GOOD) return(err);
   switch(cpu) {
      case PROC_CPU_68000:
	  /* PC, A7, SSP, and USP cannot be set to odd address */
         //if ((regId < 3) && ((regValue&3)!=0))
         if ((regId < 3) && ((regValue&1)!=0))
            return(ER_CPU_CANT_BE_ODD);
	 break;
   }
   
   /* Write the shared data member */
   curReg = regId;
//   if( regId >= nRegisters ) {
//       // write MSB into first register
//      U32 tmpVal = regValue >> 16; 
//      if((err = SdWriteMember(
//                       regTable[regPairTable[(regId-nRegisters)][0]].sdDesc,
//                       (U8 FAR *) &tmpVal,GOOD)) != GOOD) return(err);
//      // setup common variables to write LSB into second register.
//      curReg = regPairTable[(regId-nRegisters)][1];
//      regValue &= 0xffffL;
//   }

   if((err = SetReg(regTable[curReg].fwRegOrder, regValue)) != GOOD) return(err);
   if (strcmp(regTable[curReg].regName, "IMMR") == 0) {
      sim = regValue & 0xFFFF0000;
      if ((err=SdnWriteMember(SDN_SIM_ADDRESS, (U8*)&sim, GOOD)) != GOOD)
         return(err);
      if ((err = EnlEventNotify(EVENT_CPU_IMMR_EDIT))!=GOOD) return(err);
   }

   /* check frame ptr register */
   if( regId == framePtrReg ) {
      if((err = EnlEventNotify(EVENT_CPU_FP_EDIT))!=GOOD) return(err);
   }
   /* check special registers */
   switch (cpu) {
      case PROC_CPU_68000:
      case PROC_CPU_POWERPC:
	 switch (regId+SDN_REG00) {
	    case SDN_PC:
	       if((err = EnlEventNotify(EVENT_CPU_PC_EDIT))!=GOOD) return(err);
	       break;
            case SDN_SP:
               if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
               break;
            case SDN_SR:
               if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
/****
               if((err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC0_RANGE))
                      !=GOOD) return(err);
               if((err = EnlEventNotify(EVENT_MEM_MEMORY_CHANGED_SRC1_RANGE))
                      !=GOOD) return(err);
*****/
               break;

//              case SDN_SSP: {
//               break;
//              }
//              case SDN_USP: {
//               break;
//              }
	 }
           break;
   }  /* end of switch(cpu) */

   /* always generate register edited */
   if((err = EnlEventNotify(EVENT_CPU_EDIT))!=GOOD) return(err);
      
   return(GOOD);
}

/*****************************************************************************
**
**    CpuSetStockRegister
**
*****************************************************************************/
RETCODE EXPORT CpuSetStockRegister(REG_ID regId, U32 regValue) {
   RETCODE err;
   REG_ID curReg;
   PROC_CPU cpu;
   U8 width;
   U32 sim;

   /* emulation must be halted to set registers */
   if((err = BkProcessorMustBeHaltedAbsolute())!=GOOD) return(err);
 
   if ((err = ProcReturnCpu(&cpu)) != GOOD) return(err);
   switch(cpu) {
      case PROC_CPU_68000:
	  /* PC, A7, SSP, and USP cannot be set to odd address */
         //if ((regId < 3) && ((regValue&3)!=0))
         if ((regId < 3) && ((regValue&1)!=0))
            return(ER_CPU_CANT_BE_ODD);
	 break;
   }
   
   /* Write the shared data member */
   curReg = regId;

   if((err = SetReg(pStockReg[curReg].order, regValue)) != GOOD) return(err);
   if (strcmp(pStockReg[curReg].regName, "IMMR") == 0) {
      sim = regValue & 0xFFFF0000;
      if ((err=SdnWriteMember(SDN_SIM_ADDRESS, (U8*)&sim, GOOD)) != GOOD)
         return(err);
      if ((err = EnlEventNotify(EVENT_CPU_IMMR_EDIT))!=GOOD) return(err);
   }

   /* check frame ptr register */
   if( regId == framePtrReg ) {
      if((err = EnlEventNotify(EVENT_CPU_FP_EDIT))!=GOOD) return(err);
   }
   /* check special registers */
   switch (cpu) {
      case PROC_CPU_68000:
      case PROC_CPU_POWERPC:
	 switch (regId+SDN_REG00) {
	    case SDN_PC:
	       if((err = EnlEventNotify(EVENT_CPU_PC_EDIT))!=GOOD) return(err);
	       break;
            case SDN_SP:
               if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
               break;
            case SDN_SR:
               if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
               break;

	 }
           break;
   }  /* end of switch(cpu) */

   /* always generate register edited */
   if((err = EnlEventNotify(EVENT_CPU_EDIT))!=GOOD) return(err);
      
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetFpRegister
**
*****************************************************************************/
#pragma argsused /* !!! temporary until implemented */
RETCODE EXPORT CpuGetFpRegister(REG_ID regId, FPREG_VAL FAR *regValue) {
   return(ER_FP_NOT_SUPPORTED); /* !!! */
}

/*****************************************************************************
**
**    CpuSetFpRegister
**
*****************************************************************************/
#pragma argsused /* !!! temporary until implemented */
RETCODE EXPORT CpuSetFpRegister(REG_ID regId, FPREG_VAL regValue) {
   return(ER_FP_NOT_SUPPORTED); /* !!! */
}
 
/*****************************************************************************
**
**    CpuGetPC
**
*****************************************************************************/
RETCODE EXPORT CpuGetPC(DESCRIPTOR FAR *desc) {
   RETCODE err;
   ADDR_SPACE addrSpace;
   SPACE_MODE spaceMode;
   
   if ((err = GetRegAddr(0, desc)) != GOOD)
      return err;
   /* Set PC's addr space according to SR register */
   if ((err = CpuGetSpaceMode(&spaceMode)) != GOOD)
      return err;
   addrSpace = (spaceMode == SUPERVISOR_MODE) ? SPACE_SP : SPACE_UP;
   return AdrSetAddrSpace(*desc, addrSpace);
}

/*****************************************************************************
**
**    CpuSetPC
**
*****************************************************************************/
RETCODE EXPORT CpuSetPC(DESCRIPTOR desc) {
   return (SetRegAddr(0, desc));
}

/*****************************************************************************
**
**    CpuGetSP
**
*****************************************************************************/
RETCODE EXPORT CpuGetSP(DESCRIPTOR FAR *desc) {
   RETCODE err;

   if ((err = GetRegAddr(1, desc)) != GOOD)
      return err;
   return AdrSetCurrentAddrSpace(*desc);
}

/*****************************************************************************
**
**    CpuSetSP
**
*****************************************************************************/
RETCODE EXPORT CpuSetSP(DESCRIPTOR desc) {
   return (SetRegAddr(1, desc));
}

/*****************************************************************************
**
**    CpuGetFramePtr
**
*****************************************************************************/
RETCODE EXPORT CpuGetFrameptr(DESCRIPTOR FAR *desc) {
   RETCODE err;

   if ((err = GetRegAddr(framePtrReg, desc)) != GOOD)
      return err;
   return AdrSetCurrentAddrSpace(*desc);
}

/*****************************************************************************
**
**    CpuResetCPU
**
*****************************************************************************/
RETCODE EXPORT CpuResetCPU() {
   RETCODE        err;
   CPU_RESET      reset = RESET_CPU_AND_UPDATE_STATUS;
   BOOLEAN        timedOut = FALSE;

   /* Write reset command and wait for reset result form the box */
   if((err = SdWriteCmdReadResponse(resetDesc, (U8 FAR *)&reset, GOOD,
	 emulStateDesc, 0L, &timedOut))!=GOOD) return(err);

   if ((err=SdsReadResetResult()) != GOOD)
      ErrDisplayError(err,FORCE_POPUP);

   /* Generate the HALTED event on reset; this will update everyone */
   if((err = EnlEventNotify(EVENT_CPU_HALTED))!=GOOD) return(err);

   return (GOOD);
}

/*****************************************************************************
**
**    CpuResetCPUOnly
**
*****************************************************************************/
RETCODE EXPORT CpuResetCPUOnly() {
   RETCODE err;
   CPU_RESET reset = ONLY_RESET_CPU;

   /* emulation must be halted to reset only the cpu */
   if((err = BkProcessorMustBeHaltedAbsolute())!=GOOD) return(err);

   /* Write reset command and do not wait for any response */
   return(SdWriteMember(resetDesc, (U8 FAR *)&reset, GOOD));
}

/*****************************************************************************
**
**    CpuGetSignal
**
*****************************************************************************/
RETCODE EXPORT CpuGetSignal(SIG_ID sigId, U8 FAR *signalState) {

   if (sigId >= nSignals)
	  return(ER_INVALID_SIGID);
   /* Get signal state and return */
   return(SdReadMember(signalTable[sigId].sdDesc, (U8 FAR *) signalState));
}

/*****************************************************************************
**
**    CpuSetSignal
**
*****************************************************************************/
RETCODE EXPORT CpuSetSignal(SIG_ID sigId, U8 signalState) {
RETCODE err;
PROBE_TYPE specificProcessor;
U16   signals;

   if (sigId >= nSignals)
	  return(ER_INVALID_SIGID);
   /* Set the signal state and return */
   err = SdWriteMember(signalTable[sigId].sdDesc,(U8 FAR *) &signalState, GOOD);
   if (err != GOOD) return(err);
   
   if ((err = ProcReturnSpecificProcessor(&specificProcessor)) != GOOD)
      return(err);
   switch (specificProcessor) {
      case PPC603E_MP:
      case PPC860_MP:
      case PPC821_MP:
	 signals = 0;
	 if (bitReady && sigId==nSignals-1) {
	    return(iceSetReady(signalState));   
	 }
	 else {
	    for (sigId = 0; sigId < nSignals-bitReady; sigId++) {
	       err = SdReadMember(signalTable[sigId].sdDesc, (U8 FAR *)&signalState);
	       if (err != GOOD) return(err);
	       if (signalState == 1) {
		  switch (specificProcessor) {
                         case PPC603E_MP:
                              signals |= sigXlatTable603e[sigId];
			break;
                         case PPC860_MP:
                         case PPC821_MP:
                              signals |= sigXlatTable860[sigId];
			break;
		  }
	       }
	    }
	    return(Sds2AbiSetControl(signals));
	 }
      }
   return(ER_NOT_CPU);
}

/*****************************************************************************
**
**    CpuFindRegisterName
**
*****************************************************************************/
RETCODE EXPORT CpuFindRegisterName(REG_ID regId, LPSTR regName) {

   if (lstrcpy(regName, (LPSTR)stockRegName[regId]) == NULL)
      return(ER_FAILED_STRCPY);

/********
   if (regId < nRegisters) {
      if (lstrcpy(regName, (LPSTR)regTable[regId].regName) == NULL)
	 return(ER_FAILED_STRCPY);
   }
   else if (regId < (nStockRegisters+nRegPairs)) {
      if (lstrcpy(regName,
		  (LPSTR)regTable[regPairTable[(regId-nRegisters)][0]].regName)
	   == NULL) return(ER_FAILED_STRCPY);
      lstrcat(regName,":");
      if (lstrcat(regName,
		  (LPSTR)regTable[regPairTable[(regId-nRegisters)][1]].regName)
	   == NULL) return(ER_FAILED_STRCPY);
   }
   else return(ER_INVALID_REGID);
*********/
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetRegisterInfo
**
*****************************************************************************/
RETCODE EXPORT CpuGetRegisterInfo(REG_ID regId, LPSTR regName,
      U16 FAR *sortIndex, U16 FAR *type, U16 FAR *width) {
   if (regId >= nRegisters) return(ER_INVALID_REGID);
   if (regName && (lstrcpy(regName, (LPSTR)regTable[regId].regName) == NULL))
      return(ER_FAILED_STRCPY);
   if (sortIndex) *sortIndex = regTable[regId].presenterLine;
   if (type) *type = regTable[regId].numberOfFlags;
   if (width) *width = regTable[regId].regWidth;
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetRegisterValueText
**
*****************************************************************************/
RETCODE EXPORT CpuGetRegisterValueText(REG_ID regId,U16 type,LPSTR valueText) {
   RETCODE err;
   U16 i;
   U32 regValue;
   static S8 hex[] =
      { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
   if ((err = CpuGetRegister(regId, &regValue)) != GOOD) return(err);
   if (type == 0) {
      U8 width;
      if((err=CpuGetRegisterWidth(regId, &width))!=GOOD) return(err);
      sprintf(valueText,"%0*lX",(width + 3)/4,regValue);
   } else {
      S8 *valuePtr = valueText;
      for (i=0; i<regTable[regId].numberOfFlags; i++) {
	 if (regTable[regId].flagTable[i].displayAsChar) {
	    *valuePtr++ = (regValue & regTable[regId].flagTable[i].mask)
	      ? regTable[regId].flagTable[i].assertedChar
	      : regTable[regId].flagTable[i].negatedChar;
	 } else {
	    *valuePtr++ =
	       hex[(U16)((regValue & regTable[regId].flagTable[i].mask)
	       >> regTable[regId].flagTable[i].shift)];
	 }
      }
      *valuePtr = '\0';
   }
   return(GOOD);
}

/*****************************************************************************
**
**    CpuFindRegisterId
**
*****************************************************************************/
RETCODE EXPORT CpuFindRegisterId(U8 FAR *refRegName, REG_ID FAR *regId) {
   U16 i;

   /* Go through the register table and check for refRegName */
   for (i = 0; i<nRegisters; i++) {
      if (!lstrcmpi((LPSTR)refRegName, (LPSTR)regTable[i].regName)) {
	    *regId = i;
	    return(GOOD);
	  }
   }
   return(ER_REGNAME_NOT_FOUND);
}

/*****************************************************************************
**
**    CpuGetRegisterWidth
**
*****************************************************************************/
RETCODE EXPORT CpuGetRegisterWidth(REG_ID regId, U8 FAR *regWidth) {
   /* Check for valid register id */
   if (regId < nRegisters) {
      *regWidth = regTable[regId].regWidth;
      return(GOOD);
   }
   // Is it a register pair?
   if (regId < (nRegisters+nRegPairs)) {
      *regWidth = (regTable[regPairTable[regId-nRegisters][0]].regWidth
		   + regTable[regPairTable[regId-nRegisters][1]].regWidth);
      return(GOOD);
   }
   /* Bad register Id */
   return(ER_INVALID_REGID);
}

/****************************************************************************
**
**  CpuRegisterMultipleRegisters
**
*****************************************************************************/
RETCODE EXPORT CpuRegisterMultipleRegisters(REG_ID regList[2],
					    REG_ID FAR *assignedRegNum) {
   if (nRegPairs == MAX_PAIRS_SUPPORTED )
      return(ER_TOO_MANY_PAIRS);
   regPairTable[nRegPairs][0] = regList[0];
   regPairTable[nRegPairs][1] = regList[1];
   // NOTES: Nghia - 10/28/93
   // Fixed bug - Index for register pairs is off by 1.
   // Max index for regular registers will be nRegister-1
   // Max index for register pairs is the (nRegisters + nRegPairs-1)
   // Increment the nRegPairs after assignment will keep track number of
   // register correctly without assigning an invalid register Index.
   *assignedRegNum = (nRegisters + nRegPairs);
   nRegPairs++;
   return(GOOD);
}

/****************************************************************************
**
**  CpuSetFramePtrRegister
**
*****************************************************************************/
RETCODE EXPORT CpuSetFramePtrRegister(REG_ID regId) {
   // Don't let register pairs be used as frame pointer.
   if (regId >= nRegisters) return(ER_INVALID_REGID);
   framePtrReg = regId;
   return(GOOD);
}

                           /**************************** 
                            *                          *
                            *      LOCAL ROUTINES      *
                            *                          *
                            ****************************/
/****************************************************************************
**
**  GetRegAddr
**
**  Status:  TESTED
**
**  Description:
**     Retrieve the current value of the specified register and return it
**     in an Address descriptor.
**
**  Parameters:
**     input:
**        regId      Id of the register.
**     output:
**        desc       Pointer to an Address descriptor.
**
*****************************************************************************/
RETCODE PRIVATE GetRegAddr(REG_ID regId, DESCRIPTOR FAR *desc) {
   RETCODE err = GOOD;
   U32    regValue;

   /* Check if regId is a valid id */
   if (regId >= nRegisters)
	  return(ER_INVALID_REGID);

   /* Allocate an address descriptor for the Caller */
   if ((err = AdrCreateAddress(desc)) != GOOD) {
      *desc = NULL;
      return(err);
   }
   /* Get value of register */
   if ((err = CpuGetRegister(regId, (U32 FAR *) &regValue)) == GOOD)
      /* Fill in Address descriptor information */
      if ((err = AdrSetAddrOffset(*desc, regValue)) != GOOD) {
	 /* error, destroy the address descriptor */
	 AdrDestroyAddress(*desc);
		 *desc = NULL;
      }

   return(err);
}
/****************************************************************************
**
**  SetRegAddr
**
**  Status:  TESTED
**
**  Description:
**     Set an address value to the specified register.
**
**  Parameters:
**     input:
**        regId      Id of register.
**        desc       An address descriptor.
**     output:
**
**
*****************************************************************************/
RETCODE PRIVATE SetRegAddr(REG_ID regId, DESCRIPTOR desc) {
   RETCODE err = GOOD;
   U32 regValue;

   /* Check if regId is a valid id */
   if (regId >= nRegisters)
	  return(ER_INVALID_REGID);

   /* Get the address offset in the descriptor */
   if ((err = AdrGetAddrOffset(desc, (U32 FAR *)&regValue)) != GOOD)
	  return(err);
   if ((err = CpuSetRegister(regId, regValue)) != GOOD)
	  return(err);
   return(AdrDestroyAddress(desc));
}

/****************************************************************************
**
**  CpuEmulHaltedCallback
**
**  Status:  TESTED
**
**  Description:
**     Callback routine when emulation halts.
**
**  Parameters:
**     input:
**        event      Event of this callback.
**
**     output:
**        none.
**
*****************************************************************************/
VOID EXPORT CpuEmulHaltedCallback(U32 event) {
   RETCODE err;

   /*
   *** Event emulation halted occurred, registers contents changed.
   *** So notify Servers registered on CPU Server event.
	*/
   if(event == EVENT_BKPT_HALTED) {
      if((err = EnlEventNotify(EVENT_CPU_HALTED)) != GOOD)
	 ErrDisplayError(err, CHECK_MODE);
   }
}

/*****************************************************************************
**
**    CpuGetNumberOfSignals
**
*****************************************************************************/
RETCODE EXPORT CpuGetNumberOfSignals(U16 *numSignals) {
   *numSignals = nSignals;
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetSignalName
**
*****************************************************************************/
RETCODE EXPORT CpuGetSignalName(SIG_ID signalId, LPSTR name) {

   if (signalId > nSignals) return(1);

   strcpy(name, signalTable[signalId].signalName);
   
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetSpaceMode
**
*****************************************************************************/
RETCODE EXPORT CpuGetSpaceMode(SPACE_MODE FAR *spaceMode) {

   *spaceMode = USER_MODE;
   return(GOOD);
}
/******************************** E O F ***********************************/
