/****************************************************************************
**
**  Name:  cpu.c
**
**  Description:
**     Routines to access CPU registers and signals.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_68k/cpu/cpu.c_v  $
** 
**    Rev 1.1   08 Aug 1997 11:57:34   gene
** 
**    Rev 1.0   13 Feb 1997 08:44:42   gene
** Initial revision.
** 
**    Rev 1.10   29 Jul 1996 16:54:56   kevin
** added CP_RUNNING signal for 302
** 
**    Rev 1.9   21 Jun 1996 14:59:52   kevin
** added CpuGetCoreType()
** 
**    Rev 1.8   27 May 1996 13:08:16   kevin
** added 302 case
** 
**    Rev 1.7   28 Mar 1996 16:43:34   kevin
** Select the READY signal from external while initialization
** 
**    Rev 1.6   13 Feb 1996 17:07:16   kevin
** disable delay_strobe while initialization
** 
**    Rev 1.5   11 Jan 1996 14:47:52   kevin
** added 328 and 307 cases to cpusetsignal()
** 
**    Rev 1.4   09 Jan 1996 17:43:34   kevin
** added 307 and 328 cases to cpusetsignal()
** 
**    Rev 1.3   04 Dec 1995 16:09:10   kevin
** modified cpuGetPC()
** 
**    Rev 1.2   01 Dec 1995 10:46:20   kevin
** added CpuGetSpaceMode() and some notification
** 
**    Rev 1.1   06 Oct 1995 18:15:38   kevin
** Set SpuGetPC() space to SPACE_SP
** 
**    Rev 1.0   07 Sep 1995 10:10:36   gene
** Initial revision.
** 
**    Rev 1.42   06 Apr 1994 16:38:24   nghia
** Fixed Address comparison problem.
**CpuGetPC, CpuGetSP and CpuGetFrameptr() will return the address descriptor
** of whataver the current address space of the processor.  Called AdrSet
** CurrentAddrSpace() to set the appropriate address space.
** Before: the default address space for MOTO is SPACE_SD - which is data space!
** 
**    Rev 1.41   30 Mar 1994 11:34:12   john
** Added changes for 360
** 
**    Rev 1.40   03 Mar 1994 15:48:18   john
** Added GetSignalName, and GetNumberOfSignals
** 
**    Rev 1.39   01 Nov 1993 09:51:40   nghia
** Fixed bug - Invalid register index for register pairs.
** Index off by 1.
** 
**    Rev 1.38   14 Jun 1993 12:22:06   MINDY
**  Added support for register pairs.  There's a new routine that the loader
**  uses to "register" register pairs.  Also now the frame pointer can change
**  since each compiler might use a different register as the frame pointer.
** 
**    Rev 1.37   30 Mar 1993 08:28:26   ernie
** 1. Added functions needed by the new generic Actor code.
** 2. Removed tab characters.
** 3. Added code to support cpu16.
** 
**    Rev 1.36   05 Jan 1993 15:51:58   courtney
** Removed MemAlloc and related macros (no longer used).
** 
**    Rev 1.35   09 Oct 1992 14:55:42   doug
** add reset of cpu only (ppr6141)
** 
**    Rev 1.34   17 Sep 1992 11:04:24   doug
** disallow setting certain registers to odd values
** 
**    Rev 1.33   10 Sep 1992 11:45:56   doug
** change edit to remove multiple events
** 
**    Rev 1.32   08 Sep 1992 14:32:24   doug
** Changed breakpoint events.
** 
**    Rev 1.31   08 Sep 1992 09:36:06   doug
** change to new events.h event structure
** 
**    Rev 1.30   02 Sep 1992 10:43:10   doug
** emulation should be halted to set registers (no run access support).
** Leave the get registers as readable; if in emulation, the value is that
** which it was when emulation began.
** 
**    Rev 1.29   02 Sep 1992 10:30:12   doug
** a) add error check for finding reg name when index out of range
** b) boundary error in checking for register index corrected
** 
**    Rev 1.28   29 Aug 1992 07:23:02   doug
** Allow registers to be set/get while emulating.  This will avoid the
** subtle multi-tasking problems of trying to read the registers when
** emulation is about to start/stop.
** 
**    Rev 1.27   19 Aug 1992 07:15:52   doug
** add new events for when registers edited (Marilyn's request)
** 
**    Rev 1.26   14 Aug 1992 16:01:14   doug
** removed warnings
** 
**    Rev 1.25   13 Aug 1992 13:59:42   doug
** do not generate events while high level breakpoints are active (lots of
** low level breaks cause many, many events)
** 
**    Rev 1.24   06 Aug 1992 08:23:14   doug
** a) remove double event notification
** b) correct FP copy/paste error
** 
**    Rev 1.23   31 Jul 1992 13:41:14   doug
** a) init server is local (called by libmain)
** b) no register commands allowed while emulating
** c) signal set is ok while emulating
** 
**    Rev 1.22   31 Jul 1992 11:34:56   mindy
** added static to prevent server from initializing twice
** 
**    Rev 1.21   29 Jul 1992 14:41:36   john
** Changed all calls to MakeProcInstance use the dll instance
** 
**    Rev 1.20   23 Jul 1992 13:08:00   doug
** reset result was not being used and event errors were being ignored
** 
**    Rev 1.19   22 Jul 1992 16:05:50   doug
** a) calling from cli should not be special (bug)
** b) reset cpu name was wrong (resetting whole box!)
** c) indices wrong
** 
**    Rev 1.18   21 Jul 1992 12:35:12   doug
** a) the program counter (PC), stack pointer (SP), and frame pointer (FP)
** are now the 1st, 2nd, and 3rd entry in list.  This position allows the
** code to be completely processor independent.
** b) alreadyTerminated was being set true in the wrong place (init) - fixed
** 
**    Rev 1.17   21 Jul 1992 08:01:38   doug
** a) removed aliasing, now handled by firmware
** b) no 68030 files (still more generic work left)
** c) no non-runtime configuration file support anymore
** d) new generic shared data members
** e) no h/w init routine (firmware sets all values on boot up)
** f) no floating point support for now
** 
**    Rev 1.16   14 Jul 1992 12:34:22   courtney
** Fixed #ifdef bracketing.
** 
**    Rev 1.15   14 Jul 1992 12:11:32   courtney
** Reads processor-configuration table at startup.
** 
**    Rev 1.14   23 Jun 1992 15:44:48   courtney
** Include new header file, bkroot.h.
** 
**    Rev 1.13   23 Jun 1992 14:29:38   courtney
** Revised breakpoint status check to be BkProcessorMustBeHalted.
** 
**    Rev 1.12   18 May 1992 12:25:44   mindy
** reset and init register commands timing out
** 
**    Rev 1.11   14 May 1992 14:47:32   nghia
** Revised for new ErrorText interface.
** 
**    Rev 1.10   13 May 1992 09:00:58   nghia
** Added CpuGetErrorText() to support centralize error text handler.
** 
**    Rev 1.9   11 May 1992 12:55:08   nghia
** Rename ProcessorMustBeHalted to BxProcessorMustBeHalted.
** 
**    Rev 1.8   23 Apr 1992 12:09:54   nghia
** Fixed bug for Special floating-point registers FPSR, FPIAR, FPCR.
** Fixed PPR 5390. Reset - Send result to CLI, before propagate events.
** 
**    Rev 1.7   17 Apr 1992 16:16:00   nghia
** Fixed PPR 5428 - Check emulation status before set register.
** Added CLI command for FindRegisterName.
** Fixed bug in CPUFindRegisterName.
** Fixed bug in send message to CLI.
** 
**    Rev 1.6   08 Apr 1992 10:47:14   nghia
** Fixed the following PPR:
** - #5391: missing FPIAR register.
** - #5392: Set CCR register will overwrite the upper byte in SR register.
** Added routine to return register width masking pattern.
** 
**    Rev 1.5   03 Apr 1992 16:44:34   nghia
** Switched order of event register.
** 
**    Rev 1.4   02 Apr 1992 16:15:42   nghia
** Added separate events for the PC and SP registers changed.
** Fixed for PPR5279.
** 
**    Rev 1.3   27 Mar 1992 10:44:16   jim
** Fixed symbol name "EVENT_HL-BKPTEXEC_EMUL_STARTED AND HALTED.
** 
**    Rev 1.2   05 Mar 1992 13:22:38   doug
** Missing end comment commented out important lines
** 
**    Rev 1.1   01 Mar 1992 08:33:36   nghia
** Fixed bug in get register width routine.
** 
**    Rev 1.0   28 Feb 1992 11:56:52   nghia
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/cpu/cpu.c_v   1.1   08 Aug 1997 11:57:34   gene  $
**
**  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 */
U16 nRegisters;             /* number of registers */
U16 nSignals;               /* number of signales */
U16 bitReady = 1; //!! for Ready signal

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

BOOLEAN isLdrEntry=FALSE;           /* <Winky 8/7/97> */
REG_ID framePtrReg = 2;             /* 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;

/* the order of signals defined in cpu683XX.cfg should match with the following
   order and D-TACK should be the last one in config file */
/*                          AS      DS      RESET   HALT    BERR    BRQ     INT     bit 15
                                                    CP_RUN                          */
U16   sigXlatTable302[8] = {0x0040, 0x0080, 0x0400, 0x0800, 0x1000, 0x2000, 0x0001, 0x8000};
U16   sigXlatTable306[7] = {0x0040, 0x0080, 0x0400, 0x0800, 0x1000, 0x2000, 0x0001};
U16   sigXlatTable328[8] = {0x0040, 0x0080, 0x0400, 0x0800, 0x1000, 0x2000, 0x0001, 0x8000};
U16   sigXlatTable307[6] = {0x0040, 0x0080, 0x0400,         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()) != GOOD) return(err);

   /* Initialize all register descriptors */
   for (i = 0; i < nRegisters; i++) {
      /* Register with ShareData Server for its descriptor */
      if ((err = SdnRegister(SDN_REG00+i, NULLPTR,
          (DESCRIPTOR FAR *)&regTable[i].sdDesc)) != GOOD) return(err);
   }

   iceSetReady(1);  // D-TACK enable
   /* Initialize all signal descriptors */
   for (i = 0; i < nSignals; i++) {
      if ((err = SdnRegister(SDN_SIG00+i, NULLPTR, &signalTable[i].sdDesc))
	    != GOOD) return(err);
   }
   
   if (specificProcessor == M68328_MP)
      err = SdWriteMember(signalTable[nSignals-2].sdDesc,(U8 FAR *) &Disable, GOOD);

   lpCallback = MakeProcInstance((FARPROC)CpuEmulHaltedCallback, hLib);
   if ((err = EnlRegister((U32)EVENT_BKPT_HALTED,
      (EVCALLBACK)lpCallback, (DESCRIPTOR FAR *)&emuHaltedDesc)) != GOOD)
      return(err);

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

   /* Unregister all registered members of the Cpu Server */
   for (i = 0; i<nRegisters; i++) {
      /* Unregister its descriptor */
      if (regTable[i].sdDesc &&
	 ((err = SdUnRegister((DESCRIPTOR) regTable[i].sdDesc)) != 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);
   }
   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;
   U32 curVal=0L;
   if (regId >= (nRegisters+nRegPairs)) return(ER_INVALID_REGID);
   if( regId >= nRegisters ) {
      if((err=SdReadMember(regTable[regPairTable[(regId-nRegisters)][0]].sdDesc,
			   (U8 FAR *)&curVal))!=GOOD) return(err);
      curId = regPairTable[(regId-nRegisters)][1];
      curVal <<= 16;
   }
   if((err=SdReadMember(regTable[curId].sdDesc,(U8 FAR *)regValue))!=GOOD)
      return(err);
   // if handling register pairs...
   if (regId >= nRegisters) *regValue = curVal | (*regValue & 0xffffL);
   return(GOOD);
}

/*****************************************************************************
**
**    CpuSetRegister
**
*****************************************************************************/
RETCODE EXPORT CpuSetRegister(REG_ID regId, U32 regValue) {
   RETCODE err;
   REG_ID curReg;
   PROC_CPU cpu;
   U8 width;
   if (regId >= (nRegisters+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:
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	  /* PC, A7, SSP, and USP cannot be set to odd address */
	 if(( (regId==SDN_PC-SDN_REG00) || (regId==SDN_A7-SDN_REG00)
	       || (regId==SDN_USP-SDN_REG00) || (regId==SDN_SSP-SDN_REG00))
	    && ((regValue&1)!=0)) return(ER_CPU_CANT_BE_ODD);
	 break;
      case PROC_CPU_CPU16:
	 /* PK:PC and IP cannot be set to odd address */
	 if(( (regId==SDN_PCR-SDN_REG00) || (regId==SDN_IP-SDN_REG00))
	    && ((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 (!isLdrEntry) {   /* <Winky 8/7/97>  */
      if((err = SdWriteMember(regTable[curReg].sdDesc, (U8 FAR *) &regValue,
         GOOD)) != GOOD) return(err);
   }
   CpuSetLdrFlag(FALSE); /* <Winky 8/7/97> */
   
   /* check frame ptr register */
   if( regId == framePtrReg ) {
      if((err = EnlEventNotify(EVENT_CPU_FP_EDIT))!=GOOD) return(err);
   }
   /* check special registers */
   switch (cpu) {
      /*
      ** cpu16 register coupling
      **   ip -> pc, ccr
      **   pc -> ip, ccr
      **  ccr -> ip, pc
      */
      case PROC_CPU_CPU16:
	 switch (regId+SDN_REG00) {
	    case SDN_IP: {
	       U32 IP, CCR;
	       if((err = SdnReadMember(SDN_IP,(U8 FAR *)&IP)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_CCR,(U8 FAR *)&CCR)) != GOOD)
		   return(err);
	       IP+=6;  /* pk:pc = ip+6 */
	       CCR = (CCR & 0xfff0L) | ((IP>>16) & 0xfL);
	       if((err = SdnWriteMember(SDN_PCR,(U8 FAR *)&IP,GOOD)) != GOOD)
		   return(err);
	       if((err = SdnWriteMember(SDN_CCR,(U8 FAR *)&CCR,GOOD)) != GOOD)
		   return(err);
	       if((err = EnlEventNotify(EVENT_CPU_PC_EDIT))!=GOOD) return(err);
	       break;
	    }
	    case SDN_PCR: {
	       U32 PC,CCR;
	       if((err = SdnReadMember(SDN_PCR,(U8 FAR *)&PC)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_CCR,(U8 FAR *)&CCR)) != GOOD)
		   return(err);
	       CCR = (CCR & 0xfff0L) | ((PC>>16) & 0xfL);
	       PC-=6;  /* ip = pk:pc-6 */
	       if((err = SdnWriteMember(SDN_IP,(U8 FAR *)&PC,GOOD)) != GOOD)
		   return(err);
	       if((err = SdnWriteMember(SDN_CCR,(U8 FAR *)&CCR,GOOD)) != GOOD)
		   return(err);
	       if((err = EnlEventNotify(EVENT_CPU_PC_EDIT))!=GOOD) return(err);
	       break;
	    }
	    case SDN_CCR: {
	       U32 PC,CCR;
	       if((err = SdnReadMember(SDN_PCR,(U8 FAR *)&PC)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_CCR,(U8 FAR *)&CCR)) != GOOD)
		   return(err);
	       PC = (PC & 0xffffL) | ((CCR & 0xfL) << 16);
	       if((err = SdnWriteMember(SDN_PCR,(U8 FAR *)&PC,GOOD)) != GOOD)
		   return(err);
	       PC -= 6;
	       if((err = SdnWriteMember(SDN_IP,(U8 FAR *)&PC,GOOD)) != GOOD)
		   return(err);
	       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;
	 }
	 break;
      /*
      ** cpu32 register coupling
      **   a7 -> ssp or usp
      **  ssp -> a7
      **  usp -> a7
      **   sr -> a7
      */
      case PROC_CPU_68000:
      case PROC_CPU_CPU32:
      case PROC_CPU_CPU32P:
	 switch (regId+SDN_REG00) {
	    case SDN_PC:
	       if((err = EnlEventNotify(EVENT_CPU_PC_EDIT))!=GOOD) return(err);
	       break;
	    case SDN_A7: {
	       U32 SR, A7;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_A7,(U8 FAR *)&A7)) != GOOD)
		   return(err);
	       if((SR & 0x2000) != 0) {    /* supervisor mode: A7 -> SSP */
		  if((err = SdnWriteMember(SDN_SSP,(U8 FAR *)&A7,GOOD))!=GOOD)
		     return(err);
	       } else {                    /* user mode: A7 -> USP */
		  if(( err = SdnWriteMember(SDN_USP,(U8 FAR *)&A7,GOOD))!=GOOD)
		     return(err);
	       }
	       if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
	       break;
	    }
	    case SDN_SR: {
	       U32 SR, A7;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		   return(err);
	       if((SR & 0x2000) != 0) {  /* supervisor state */
		  if((err = SdnReadMember(SDN_SSP,(U8 FAR *)&A7)) != GOOD)
		      return(err);
	       } else {
		  if((err = SdnReadMember(SDN_USP,(U8 FAR *)&A7)) != GOOD)
		      return(err);
	       }
	       if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&A7,GOOD)) != GOOD)
		  return(err);
	       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: {
	       U32 SR, Ssp;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		  return(err);
	       if((err = SdnReadMember(SDN_SSP,(U8 FAR *)&Ssp)) != GOOD)
		  return(err);
	       if((SR & 0x2000) != 0) {
		  if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&Ssp,GOOD))!=GOOD)
		     return(err);
		  if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD)
		     return(err);
	       }
	       break;
	    }
	    case SDN_USP: {
	       U32 SR, Usp;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_USP,(U8 FAR *)&Usp)) != GOOD)
		   return(err);
	       if((SR & 0x2000) == 0) {
		  if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&Usp,GOOD))!=GOOD)
		     return(err);
		  if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD)
		      return(err);
	       }
	       break;
	    }
	 }
	 break;   /* end of cpu32 case */
      case PROC_CPU_68040:
	 switch (regId+SDN_REG00) {
	    case SDN_PC:
	       if((err = EnlEventNotify(EVENT_CPU_PC_EDIT))!=GOOD) return(err);
	       break;
	    case SDN_A7: {
	       U32 SR, A7;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_A7,(U8 FAR *)&A7)) != GOOD)
		   return(err);
	       if((SR & 0x2000) != 0) { /* supervisor mode */
		  if((SR & 0x1000) != 0) {
		     /* supervisor master mode: A7 -> MSP */
		     if((err = SdnWriteMember(SDN_MSP,(U8 FAR *)&A7,GOOD))!=GOOD)
			return(err);
		  } else {
		     /* supervisor interrupt mode: A7 -> ISP */
		     if((err = SdnWriteMember(SDN_ISP,(U8 FAR *)&A7,GOOD))!=GOOD)
			return(err);
		  }
	       } else {                    /* user mode: A7 -> USP */
		  if(( err = SdnWriteMember(SDN_USP,(U8 FAR *)&A7,GOOD))!=GOOD)
		     return(err);
	       }
	       if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
	       break;
	    }
	    case SDN_SR: {
	       U32 SR, A7;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		   return(err);
	       if((SR & 0x2000) != 0) {  /* supervisor state */
			      if((SR & 0x1000) != 0) {
				     /* supervisor master mode */
		     if((err = SdnReadMember(SDN_MSP,(U8 FAR *)&A7)) != GOOD)
			 return(err);
				  } else {
				     /* supervisor interrupt mode */
		     if((err = SdnReadMember(SDN_ISP,(U8 FAR *)&A7)) != GOOD)
			 return(err);
				  }
	       } else {
		  if((err = SdnReadMember(SDN_USP,(U8 FAR *)&A7)) != GOOD)
		      return(err);
	       }
	       if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&A7,GOOD)) != GOOD)
		  return(err);
	       if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD) return(err);
	       break;
	    }
	    case SDN_MSP: {
	       U32 SR, Ssp;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		  return(err);
	       if((err = SdnReadMember(SDN_MSP,(U8 FAR *)&Ssp)) != GOOD)
		  return(err);
	       if((SR & 0x3000) == 0x3000) {
		  if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&Ssp,GOOD))!=GOOD)
		     return(err);
		  if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD)
		     return(err);
	       }
	       break;
	    }
	     case SDN_ISP: {
	       U32 SR, Ssp;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		  return(err);
	       if((err = SdnReadMember(SDN_ISP,(U8 FAR *)&Ssp)) != GOOD)
		  return(err);
	       if((SR & 0x3000) == 0x2000) {
		  if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&Ssp,GOOD))!=GOOD)
		     return(err);
		  if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD)
		     return(err);
	       }
	       break;
	    }
	   case SDN_USP: {
	       U32 SR, Usp;
	       if((err = SdnReadMember(SDN_SR,(U8 FAR *)&SR)) != GOOD)
		   return(err);
	       if((err = SdnReadMember(SDN_USP,(U8 FAR *)&Usp)) != GOOD)
		   return(err);
	       if((SR & 0x2000) == 0) {
		  if((err = SdnWriteMember(SDN_A7,(U8 FAR *)&Usp,GOOD))!=GOOD)
		     return(err);
		  if((err = EnlEventNotify(EVENT_CPU_SP_EDIT))!=GOOD)
		      return(err);
	       }
	       break;
	    }
	 }
	 break;   /* end of 68040 case */
   }  /* 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);

   /* 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 M68302_MP:
      case M68306_MP:
      case M68307_MP:
      case M68328_MP:
	 signals = 0;
	 if (bitReady && sigId==nSignals-1) {
              return(iceSetReady(signalState));   // D-TACK signal
	 }
	 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 M68302_MP:
                              signals |= sigXlatTable302[sigId];
			break;
		     case M68306_MP:
			signals |= sigXlatTable306[sigId];
			break;
		     case M68328_MP:
			signals |= sigXlatTable328[sigId];
			break;
		     case M68307_MP:
			signals |= sigXlatTable307[sigId];
			break;
		  }
	       }
	    }
	    return(Sds2AbiSetControl(signals));
	 }
      default:
	 return(ER_NOT_CPU);
      }
   return (GOOD);
}

/*****************************************************************************
**
**    CpuFindRegisterName
**
*****************************************************************************/
RETCODE EXPORT CpuFindRegisterName(REG_ID regId, LPSTR regName) {
   if (regId < nRegisters) {
      if (lstrcpy(regName, (LPSTR)regTable[regId].regName) == NULL)
	 return(ER_FAILED_STRCPY);
   }
   else if (regId < (nRegisters+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) {
U32 regSR;
RETCODE err;

   if ((err = CpuGetRegister(SDN_SR-SDN_REG00, &regSR)) != GOOD)
      return(err);
   *spaceMode = (regSR & 0x2000) ? SUPERVISOR_MODE : USER_MODE;
   return(GOOD);
}

/*****************************************************************************
**
**    CpuGetSpaceMode
**
*****************************************************************************/
RETCODE EXPORT CpuGetCoreType(U16 FAR *coreType) {
RETCODE err;

   if ((err = Sds2AbiGetCoreType(coreType)) != GOOD)
      return(err);

   return(GOOD);
}
/*****************************************************************************
**
**    CpuSetLdrFlag
**    <Winky 8/7/97>
*****************************************************************************/
RETCODE EXPORT CpuSetLdrFlag(BOOLEAN FAR LdrSetFlag) {

   isLdrEntry=LdrSetFlag;
   return(GOOD);
}
/******************************** E O F ***********************************/
