/****************************************************************************
**
**  Name:  treg.cpp
**
**  Description:
**     Source file for peripheral server treg component.
**
**  $Log:   S:/tbird/arcppc/peri/treg.cpv  $
** 
**    Rev 1.6   08 Apr 1998 10:52:44   hera
** For ppc821
** 
**    Rev 1.5   28 Nov 1997 15:31:18   kevin
** get string value by strtoul() instead of strtol()
** 
**    Rev 1.4   28 Aug 1997 10:02:52   cjchen
** 
**    Rev 1.3   27 Aug 1997 13:57:06   cjchen
** 
**    Rev 1.0.1.0   21 Aug 1997 11:56:46   cjchen
** 
**    Rev 1.0   17 Jan 1997 08:47:44   kevin
** Initial revision.
** 
**    Rev 1.4   17 Dec 1996 10:51:18   gene
** added 5204
** 
**    Rev 1.3   28 Nov 1996 17:09:16   gene
** added cpu_reg text string
** 
**    Rev 1.2   13 Sep 1996 10:30:18   gene
** added internal register function for peri
** 
**    Rev 1.1   23 Aug 1996 13:46:02   gene
** added cache register, peri window
** 
**    Rev 1.0   03 Jun 1996 11:09:28   gene
** Initial revision.
** 
**    Rev 1.3   19 Jan 1996 16:18:58   kevin
** update peri window after changing content of a register
** 
**    Rev 1.2   10 Jan 1996 18:26:42   kevin
** modified TRegister::SetValue() to handle with 307 and 328 cases
** 
**    Rev 1.1   01 Dec 1995 17:21:54   kevin
** turned off verify before writing data to memory
** 
**    Rev 1.0   07 Sep 1995 09:49:40   gene
** Initial revision.
** 
**    Rev 1.28   03 May 1994 09:48:30   nghia
** Added initialization for the TReg object.  Also, destroy the fieldInfo list
** when object is destroyed.
** 
**    Rev 1.27   21 Apr 1994 16:29:54   john
** Added code to check the SIM_VALID sd member
** 
**    Rev 1.26   19 Apr 1994 16:37:20   nghia
** Fixed PPR 9256, 9257 - Handle error reading peripherals.
** Revised to follow coding standard.
** Added GetFormatValue() method to format register value to ? when error.
** Major cleanup for memory and address descriptor leakage.
** 
**    Rev 1.25   23 Nov 1993 11:02:06   ron
** More U8->U16 conversions
** 
**    Rev 1.24   23 Nov 1993 10:27:16   ron
** 255 -> 256 buffer size problem
** 
**    Rev 1.23   22 Nov 1993 16:23:46   ron
** fixes for PPRs 9155,9173,9175
** 
**    Rev 1.22   17 Nov 1993 16:20:30   ron
** last minute buffer writing problem found by Paul
** 
**    Rev 1.21   17 Nov 1993 15:27:16   ron
** fix for ppr9100
** 
**    Rev 1.20   17 Nov 1993 14:10:36   ron
** No change.
** 
**    Rev 1.19   16 Nov 1993 08:33:54   ron
** Fix for buffer save during ESC bug.
** 
**    Rev 1.18   15 Nov 1993 14:27:00   ron
** byte ordering bugs fixed
** 
**    Rev 1.17   12 Nov 1993 15:58:46   ron
** fix (I think) for the 331/332 MM bit setting problem.
** 
**    Rev 1.16   10 Nov 1993 16:05:58   ron
** fixes for 9066, 9063, 9069, 9070
** 
**    Rev 1.15   09 Nov 1993 10:48:20   ron
** debugging 340 MBAR stuff
** 
**    Rev 1.14   08 Nov 1993 15:59:20   ron
** bug fixes for pv2.1
** 
**    Rev 1.13   05 Nov 1993 10:04:20   ron
** removed unnecessary testfunc.h
** 
**    Rev 1.12   04 Nov 1993 10:35:30   ron
** misc bug fixes
** 
**    Rev 1.11   03 Nov 1993 13:46:58   ron
** ready for first build of 2.1
** 
**    Rev 1.10   22 Oct 1993 09:44:16   ron
** fixed buffer write UAE/etc bug
** 
**    Rev 1.9   21 Oct 1993 15:15:46   ron
** bug fixes based on testing for release
** 
**    Rev 1.8   20 Oct 1993 14:14:38   ron
** ready for pv2.1 (sorta)
** 
**    Rev 1.7   18 Oct 1993 08:40:38   ron
** checkpoint
** 
**    Rev 1.6   15 Oct 1993 11:15:08   ron
** ready to build and debug
** 
**    Rev 1.5   14 Oct 1993 12:41:34   ron
** checkpoint
** 
**    Rev 1.4   12 Oct 1993 14:44:18   ron
** checkpoint after buffer editing
** 
**    Rev 1.3   05 Oct 1993 17:16:12   marilyn
** Fixed bug where register object did not create a buffer if it was
** a buffer type register.
** 
**    Rev 1.2   04 Oct 1993 16:38:08   marilyn
** Updated member functions.
** 
**    Rev 1.1   30 Sep 1993 16:44:16   ron
** bug fixes for reader
** 
**    Rev 1.0   30 Sep 1993 13:41:38   ron
** Initial revision.
** 
**  $Header:   S:/tbird/arcppc/peri/treg.cpv   1.6   08 Apr 1998 10:52:44   hera  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#define STRICT
#define WIN31

#ifndef _PERISERV_
#include "periserv.h"
#endif

#ifndef _PERIPRES_
#include "peripres.h"
#endif

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

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

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

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

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

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

#ifndef _SDNUM_
#include "sdnum.h"
#endif

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

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

// BorlandC includes
#ifndef __CTYPE_H
#include <ctype.h>
#endif

#ifndef __STDIO_H
#include <stdio.h>
#endif

#ifndef __ASSOC_H
#include <assoc.h>
#endif

#ifndef __LIST_H
#include <list.h>
#endif



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


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

extern PTPeriServer PeriServer;   // Peripheral server object ptr
extern PTGroup firstGroup;

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

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
//****************************************************************************
//  TRegister
//
//  Description:
//     Register object used to contain all register information.  
//****************************************************************************

//-----------------------------------------------------------------------------
// TRegister Ctor
//-----------------------------------------------------------------------------
TRegister::TRegister(HFILE hFile, U32 grp, U16 line) : description("None"),
                                                       statusInfo("None"),
                                                       fieldInfo() {
   LPSTR lpTok;
   S32 lTmp;
   U32 uTmp;
   PTField field;
   CHAR *endptr, linebuf[MAX_INFOSTR];
   S16 buttonValue, fieldPos, sumSize, regSize;
 
   dirty        = TRUE;
   watched      = FALSE;
   view         = SUMMARY;
   groupId      = grp;
   bufferValue  = NULL;
   next         = NULL;
   this->status = ER_PP_READING_REG; // error if we return early...
   errLine      = line;
   errField     = 0;
   nLines       = 1;
   expanded     = FALSE;
   nLinesDirty  = FALSE;
   // 04/29/94 - Nghia
   // Force the fieldInfo DoubleList object owns its containing objects
   fieldInfo.ownsElements(1);
   
   // find mnemonic
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   lpTok = _fstrtok(linebuf, WhiteSpace);
   if (lpTok == NULL) return;
   _fstrncpy((LPSTR)name, lpTok, MAX_MNEMONIC - 1);
   name[MAX_MNEMONIC - 1] = '\0'; // make extra sure it's null terminated

   // find offset_from_peri_start_range
   errField = 1;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtoul(lpTok, &endptr, 0);
   addrOffset = (U32) lTmp;

   // find #bytes
   errField = 2;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0 || lTmp > 256) return;
   size = (U16) lTmp;

   // find #fields
   errField = 3;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0 || lTmp > 256) return;
   fieldCnt = (U16) lTmp;

   // find unusedFieldbitmask
   errField = 4;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   uTmp = strtoul(lpTok, &endptr, 0);
   unusedBitMask = (U32) uTmp;

   // find multiWrites?
   errField = 5;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   uTmp = strtoul(lpTok, &endptr, 0);
   multiWrites = (BOOLEAN) (uTmp != 0);

   // find multiWritesBitmask
   errField = 6;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   uTmp = strtoul(lpTok, &endptr, 0);
   multiWritesBitMask = (U32) uTmp;

   // find buffer?
   errField = 7;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   uTmp = strtoul(lpTok, &endptr, 0);
   buffer = (BOOLEAN) (uTmp != 0);
   if (!buffer)
      bufferValue = NULL;
   else {
      bufferValue = (LPU8)TMalloc(fieldCnt);
      memset(bufferValue,'\0',fieldCnt);
   }

   // find noReads (optional)
   errField = 8;
   lpTok = _fstrtok(NULL, WhiteSpace);
   noReads = noWrites = FALSE;
   if (lpTok != NULL) {
      uTmp = strtoul(lpTok, &endptr, 0);
      noReads = (BOOLEAN) (uTmp != 0);
      // find noWrites (optional)
      errField = 9;
      lpTok = _fstrtok(NULL, WhiteSpace);
      if (lpTok != NULL) {
         uTmp = strtoul(lpTok, &endptr, 0);
         noWrites = (BOOLEAN) (uTmp != 0);
      }
   }

   // find description string
   errField = 0;
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   // fstrtok behaves differently if it's starting with one of str2's chars...
   if (linebuf[0] == '"') {
     lpTok = _fstrtok(linebuf, "\"");
     if (lpTok == NULL) return;
   }
   else {
     lpTok = _fstrtok(linebuf, "\"");
     if (lpTok == NULL) return;
     lpTok = _fstrtok(NULL, "\"");
     if (lpTok == NULL) return;
   }
   description = String(lpTok);

   // find status line
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   if (linebuf[0] == '"') {
     lpTok = _fstrtok(linebuf, "\"");
     if (lpTok == NULL) return;
   }
   else {
     lpTok = _fstrtok(linebuf, "\"");
     if (lpTok == NULL) return;
     lpTok = _fstrtok(NULL, "\"");
     if (lpTok == NULL) return;
   }
   statusInfo = String(lpTok);

   sumSize = 0;
   if (!buffer && fieldCnt > 0) {
      // find start_fields line
      if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
         MAX_INFOSTR) != GOOD) return;
      lpTok = _fstrtok(linebuf, WhiteSpace);
      if (lpTok == NULL) return;
      if (_fstrncmp(lpTok,(LPSTR)"start_fields", strlen("start_fields")) != 0)
         return;
      for (lTmp = 0; lTmp < fieldCnt; lTmp++) {
         field = new TField(hFile, errLine);
         field->parent = this;
         this->errLine = field->errLine;
         if (field->status != GOOD) {
            this->errField = field->errField;
            this->status = field->status;
            delete field;
            return;
         }
         else {
            fieldPos = field->GetFieldLocation() - field->GetSize() + 1;
            regSize = size * 8; // in bits
            sumSize += field->GetSize();
            if (fieldPos < 0 || regSize < (fieldPos + field->GetSize())) {
               sprintf(linebuf,
                  "size/pos inconsistency with reg: %s, field: %s", 
                  GetName(NULL),field->GetName(NULL));
               ErrMessageBox((LPSTR) "Config File Error", 
                 (LPSTR) linebuf,
                 MB_OK | MB_ICONEXCLAMATION,
                 HE_EDITPERIPHREG, (S16 FAR *) &buttonValue);
            }
         }
         // IMPORTANT
         // Adding TField object to the fieldInfo container
         this->AddFieldInfo(*field);
      }
      this->status = ER_PP_READING_REG; // use this error if we return early...
   }
   regSize = size * 8; // in bits
   if (regSize < sumSize) {
      sprintf(linebuf, "likely field overlap in register: %s", GetName(NULL));
      ErrMessageBox((LPSTR) "Config File Warning", 
        (LPSTR) linebuf,
        MB_OK | MB_ICONEXCLAMATION,
        HE_EDITPERIPHREG, (S16 FAR *) &buttonValue);
   }
   // find end_reg line
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   lpTok = _fstrtok(linebuf, WhiteSpace);
   if (lpTok == NULL) return;
   if (_fstrncmp(lpTok,(LPSTR)"end_reg", strlen("end_reg")) != 0)
      return;
   this->status = GOOD;
   return;
}

//-----------------------------------------------------------------------------
// TRegister Dtor
//-----------------------------------------------------------------------------
TRegister::~TRegister() {
   // Destroy the buffer
   if (bufferValue != NULL)
      TFree(bufferValue);
   // Destroy the TField objects in list  
   if (fieldInfo.getItemsInContainer() > 0) 
      fieldInfo.flush();
}

//-----------------------------------------------------------------------------
// CountLines
//-----------------------------------------------------------------------------
U32 TRegister::CountLines() {
   U32 tmpCnt = 0L;
   if (!expanded) {
      nLines = 1;
      nLinesDirty = FALSE;
      return (1L);
   }
   if (nLinesDirty) {
      if (!buffer) {
        tmpCnt = fieldCnt;
      }
      else {
        tmpCnt = fieldCnt / size;
        tmpCnt = (tmpCnt + 7) / 8;
      }
      nLines = tmpCnt + 1;
      nLinesDirty = FALSE;
   }
   return (nLines);
}


// Register summary format is as follows:
//     register address,mnemonic,value,description
// Buffer summary format is as follows:
//     register address,mnemonic, description
//-----------------------------------------------------------------------------
// FormatRegister
//-----------------------------------------------------------------------------
CHAR CPU_REG_STR[5][9] = { "CPU @002", "CPU @004", "CPU @005", "CPU @C04",
            "CPU @C0F" };
RETCODE TRegister::FormatRegister(LPSTR text) {
   S8 regAddr[32];
   S8 value[32];
   S8 desc[MAX_INFOSTR];
   DESCRIPTOR tmpDesc = NULL;
   U16 offset16,strIdx;

   regAddr[0] = '\0';
   value[0] = '\0';
   desc[0] = '\0';
   text[0] = '\0';
   
   if ((status = PeriServer->GetRegisterAddress(this,&tmpDesc)) != GOOD) {
      if (tmpDesc != NULL) AdrDestroyAddress(tmpDesc);
      return status;
   }
   if ((status = AdrConvAddressToTextWithParams(tmpDesc,FALSE,TRUE, regAddr)) 
      != GOOD) {
      if (tmpDesc != NULL) AdrDestroyAddress(tmpDesc);      
      return status;
   }
   
   offset16 = (U16)(GetAddrOffset() & 0xFFFF);
   
   // ReadMem for the latest value
   if (IsDirty() || (status != GOOD)) {
      status = PeriServer->ReadRegValue(this, tmpDesc);
      // failed to read register value, force it to be reread again next time
      dirty = (status != GOOD);
   }
        
   if (tmpDesc != NULL)
      AdrDestroyAddress(tmpDesc);
   
   // Begin Formatting   
   GetFormatValue(value);
   text[0] = '\0';
   if (fieldCnt == 0) {
      strcat(text,"    \t");
   }
   else if (expanded) {
      strcat(text,"  (-)\t");
   }
   else {
      strcat(text,"  (+)\t");
   }
   if ((offset16 & 0xFFF0) == 0xFFF0) {
      strIdx = offset16 & 0x0F;
      strcat(text,CPU_REG_STR[strIdx]);
   } else
      strcat(text,regAddr);
   strcat(text,"\t");
   if (!buffer) {
      strcat(text,value);
      strcat(text,"\t");
   }
   else {
      strcat(text,"   ");
      strcat(text,"\t");
   }
   strcat(text,name);
   strcat(text,"\t");
   GetDesc(desc);
   strcat(text,desc);
   return status;
}

//-----------------------------------------------------------------------------
// LineToText
//-----------------------------------------------------------------------------
LPSTR TRegister::LineToText(U32 lLine, LPSTR text) {
   CHAR tempStr[MAX_INFOSTR];
   PTRegister tmpReg;
   PTField field = NULL;
   LPSTR fieldDesc = NULL;
   static CHAR statTempVal[32];
   U8 tmpU8;
   U16 bufByteOffset, tmpU16,i, n, maxn;
   U32 tmpCnt = 0L, pLines, tmpU32, Loc;
   LPU8 tmpBufPtr = NULL, bufPtr = NULL;

   lLine--; // subtract one for the name of the register itself
   tmpCnt = CountLines();
   if (lLine >= tmpCnt) lLine = tmpCnt - 1;
   if (!buffer) { // format a field
      field = GetFieldInfo(lLine);
      if (field != NULL) {
         field->GetName(tempStr);
         strcat(tempStr,"\t");
         fieldDesc = tempStr + lstrlen(tempStr);
         field->LookupFieldDesc(fieldDesc,NULL);
         tmpU16 = field->GetSize() - 1;
         Loc = field->GetFieldLocation();
         if (tmpU16 > 0) 
            sprintf(text,"\t%lu-%lu:\t  %lX\t%Fs", Loc, Loc-tmpU16,
                 (U32) field->GetValue(), (LPSTR) tempStr);
         else
            sprintf(text,"\t%lu:\t  %lX\t%Fs", Loc, 
                 (U32) field->GetValue(), (LPSTR) tempStr);
      }
   }
   else {
      bufPtr = GetBufferValue();
      sprintf(text,"\t(+%3.3ld)\t", (S32)(lLine * size * 8));
      n = lLine * 8;
      maxn = fieldCnt / size;
      for (i = 0; i < 8 && n < maxn; i++, n++) {
         tmpBufPtr = bufPtr + (lLine * size * 8) + (i * size);
         statTempVal[0] = ' ';
         statTempVal[1] = '\0';
         switch(size) {
         case 1:
            tmpU8 = *((U8 *) tmpBufPtr);
            sprintf(statTempVal,"%2.2lX ", (U32) tmpU8);
            break;
         case 2:
            tmpU16 = *((U16 *) tmpBufPtr);
            tmpU16 = MemSwapBytesInWord(tmpU16);
            sprintf(statTempVal,"%4.4lX ", (U32) tmpU16);
            break;
         case 4:
            tmpU32 = *((U32 *) tmpBufPtr);
            tmpU32 = MemSwapBytesInLong(tmpU32);
            sprintf(statTempVal,"%8.8lX ", (U32) tmpU32);
            break;
         }
         strcat(text, statTempVal);
      }
   }
   // unable to read memory for register
   if (status != GOOD) {
      // format the field and buffer into ?
      if (((bufPtr = strchr(text, '\t')) != NULL) &&
          (bufPtr++ != NULL) && ((bufPtr = strchr(bufPtr, '\t')) != NULL) &&
          (bufPtr++ != NULL)) {
          tmpBufPtr = bufPtr;
          for (i = 0; i < strlen(tmpBufPtr) && ((*bufPtr) != '\t'); i++) {
             if (isxdigit(*bufPtr)) 
                *bufPtr = (CHAR)'?';
             // next character
             bufPtr++;
          }
      }
   }
      
   return (text);
}

//-----------------------------------------------------------------------------
// GetName
//-----------------------------------------------------------------------------
LPSTR TRegister::GetName(LPSTR text) const {
    if (text != NULL)
       strcpy(text,name);
    return ((LPSTR)name);
}

//-----------------------------------------------------------------------------
// GetAddrOffset
//-----------------------------------------------------------------------------
U32 TRegister::GetAddrOffset() { 
   return addrOffset; 
}

//-----------------------------------------------------------------------------
// GetGroupId
//-----------------------------------------------------------------------------
U32 TRegister::GetGroupId() { 
   return groupId; 
}

//-----------------------------------------------------------------------------
// GetSize
//-----------------------------------------------------------------------------
U16 TRegister::GetSize() { 
   return size; 
}

//-----------------------------------------------------------------------------
// GetFieldCnt
//-----------------------------------------------------------------------------
U16 TRegister::GetFieldCnt() { 
   return fieldCnt; 
}

//-----------------------------------------------------------------------------
// GetUnusedBitMask
//-----------------------------------------------------------------------------
U32 TRegister::GetUnusedBitMask() { 
   return unusedBitMask; 
}

//-----------------------------------------------------------------------------
// GetWritePermission
//-----------------------------------------------------------------------------
BOOLEAN TRegister::GetWritePermission() { 
   return (!noWrites); 
}

//-----------------------------------------------------------------------------
// GetReadPermission
//-----------------------------------------------------------------------------
BOOLEAN TRegister::GetReadPermission() { 
   return (!noReads); 
}

//-----------------------------------------------------------------------------
// GetMultiWritesBitMask
//-----------------------------------------------------------------------------
U32 TRegister::GetMultiWritesBitMask() { 
   return multiWritesBitMask; 
}

//-----------------------------------------------------------------------------
// IsBuffer
//-----------------------------------------------------------------------------
BOOLEAN TRegister::IsBuffer() { 
   return buffer; 
}

//-----------------------------------------------------------------------------
// GetDesc
//-----------------------------------------------------------------------------
LPSTR TRegister::GetDesc(LPSTR text) const{
   if (text != NULL)
      strcpy(text, (const char *)description);
   return(text);
}

//-----------------------------------------------------------------------------
// GetStatusInfo
//-----------------------------------------------------------------------------
LPSTR TRegister::GetStatusInfo(LPSTR text) const {
   if (text != NULL)
      strcpy(text,(const char *)statusInfo);
   return((char *) ((const char *)statusInfo));
}

//-----------------------------------------------------------------------------
// IsDirty
//-----------------------------------------------------------------------------
BOOLEAN TRegister::IsDirty() { 
   return dirty; 
}

//-----------------------------------------------------------------------------
// SetDirty
//-----------------------------------------------------------------------------
VOID TRegister::SetDirty() { 
   dirty = TRUE; 
}

//-----------------------------------------------------------------------------
// GetValue
//-----------------------------------------------------------------------------
U32 TRegister::GetValue() { 
   SetFieldValues(); // possible performance problem?
   return value.GetValue(); 
}

//-----------------------------------------------------------------------------
// SetValue
//-----------------------------------------------------------------------------
RETCODE TRegister::SetValue(U32 newValue,DESCRIPTOR address /* = NULL */) {
   RETCODE err = GOOD;
   LPU8 memBufferPtr= NULL;
   U8 tmpValueB;
   U16 tmpValueW, offset16;
   U32 tmpValueDW, oldVal;
   S8 buf[32];
   S16 buttonID;
   BOOLEAN setMCR = FALSE, simValid;
   BOOLEAN origVerifyFlag, changeFlag = FALSE;
   PTGroup tmpGroup;
   PROBE_TYPE proc;
   
   // write to memory if address is valid
   if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
      return(err);

   if (proc == M68307_MP || proc == M68328_MP || proc == MCF5202_MP ||
       proc == MCF5204_MP || proc == PPC860_MP || proc == PPC821_MP) {
      if (GetWritePermission()) {
         if (address) {
            offset16 = (U16)(GetAddrOffset() & 0xFFFF);
            if ((err = Sds2AbiSetIntReg(offset16,size,newValue)) != GOOD)
               return(err);
            if ((err = PeriInvalidateDisplay()) != GOOD)
               return(err);
         }
         if (err != GOOD)
            dirty = TRUE;
         else {
            value.SetValue(newValue);
            SetFieldValues();
            dirty = FALSE;
         }
      }
   } else {
      if (address) {
         if(PeriServer->HasMBAR() && stricmp("MBAR", name) != 0) {
            err = PeriServer->SaveMBAR();
         }
         else if (PeriServer->HasMBAR()) {
            err = PeriServer->SetMBAR(newValue);
         }
         else {
            if (stricmp("MCR", name) == 0) {
                setMCR = TRUE;
                if ((newValue & 0x40) == 0) { // setting it to 3FF
                   if (SdnReadMember(SDN_SIM_VALID, (U8 *)&simValid) == GOOD) {
                      if (simValid) {
                         if (SdnReadMember(SDN_SIM_ADDRESS,(LPU8)buf) == GOOD) {
                            oldVal = *(U32 *)buf;
                            oldVal = (oldVal & (~(0x800000)));
                            for (tmpGroup = firstGroup; tmpGroup != NULL;
                                 tmpGroup = tmpGroup->next) {
                                    tmpGroup->ResetBase(oldVal);
                                 }
                         }
                      }
                   }
                }
            }
         }
         if (err == GOOD) {
            // TFreed by the MemWrite
            if ((memBufferPtr = (LPU8)TMalloc(sizeof(newValue))) == NULL)
               return ER_OUT_OF_MEMORY;
            MemGetVerifyWrites(&origVerifyFlag);
            if (origVerifyFlag == TRUE) {
               MemSetVerifyWrites(FALSE);
               changeFlag = TRUE;
            }
            switch(size) {
               case BYTE_SIZE:
                  tmpValueB = (U8) (newValue & unusedBitMask);
                  *((U32 *)memBufferPtr) = tmpValueB;
                  err = MemWriteSized(address,size,memBufferPtr,BYTE_SIZE);
                  break;
               case WORD_SIZE:
                  tmpValueW = (U16) (newValue & unusedBitMask);
                  tmpValueW = MemSwapBytesInWord(tmpValueW);
                  *((U32 *)memBufferPtr) = tmpValueW;
                  err = MemWriteSized(address,size,memBufferPtr,WORD_SIZE);
                  break;
               case DWORD_SIZE:
                  tmpValueDW = (U32) (newValue & unusedBitMask);
                  tmpValueDW = MemSwapBytesInLong(tmpValueDW);
                  *((U32 *)memBufferPtr) = tmpValueDW;
                  err = MemWriteSized(address,size,memBufferPtr,DWORD_SIZE);
                  break;
            }
            if (changeFlag)
               MemSetVerifyWrites(origVerifyFlag);
            if (!setMCR && err != GOOD) {
               ErrDisplayFormattedError(err, FORCE_POPUP,NULL,NULL,NULL,MB_OK,
                   (S16 FAR *) &buttonID);
            }
         }
         if(PeriServer->HasMBAR() && stricmp("MBAR", name) != 0) {
            err = PeriServer->RestoreMBAR();
         }
      } // if (address)

      if (!setMCR && err != GOOD)
         dirty = TRUE;
      else {
         value.SetValue(newValue);
         SetFieldValues();
         dirty = FALSE;
         if (setMCR) err = MapConfigCS();
      }
   }
   return err;
}

//-----------------------------------------------------------------------------
// GetBufferValue
//-----------------------------------------------------------------------------
LPU8 TRegister::GetBufferValue() {  return bufferValue; }

//-----------------------------------------------------------------------------
// SetValue
//-----------------------------------------------------------------------------
RETCODE TRegister::SetValue(LPU8 newValueBuffer,
                            DESCRIPTOR address /* = NULL */) {
   RETCODE err = GOOD;
   LPU8 memBufferPtr;
   BOOLEAN origVerifyFlag, changeFlag = FALSE;
   U16 offset16;
   PROBE_TYPE proc;

   if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
      return(err);

   if (newValueBuffer == NULL)
      return ER_PP_INVALID_VALUE;

   if (proc == M68307_MP || proc == M68328_MP || proc == MCF5202_MP ||
       proc == MCF5204_MP || proc == PPC860_MP || proc == PPC821_MP) {
      if (GetWritePermission())
         if (address) {
            offset16 = (U16)(GetAddrOffset() & 0xFFFF);
            if ((err = Sds2AbiSetIntReg(offset16,size,(U32)(*newValueBuffer))) != GOOD)
               return(err);
            if ((err = PeriInvalidateDisplay()) != GOOD)
               return(err);
         }
   } else {
      if (address) {
         if ((memBufferPtr = TMalloc(fieldCnt)) == NULL)   // Tfreed by MemWrite
            return ER_OUT_OF_MEMORY;
         // make a copy of the new value, this is from MemReadSized
         memcpy(memBufferPtr,newValueBuffer,fieldCnt);
         MemGetVerifyWrites(&origVerifyFlag);
         if (origVerifyFlag == TRUE) {
            MemSetVerifyWrites(FALSE);
            changeFlag = TRUE;
         }
         if (size == 1) {
            err = MemWriteSized(address,fieldCnt,memBufferPtr,BYTE_SIZE);
         }
         else if (size == 2) {
            err = MemWriteSized(address,fieldCnt,memBufferPtr,WORD_SIZE);
         }
         else if (size == 4) {
            err = MemWriteSized(address,fieldCnt,memBufferPtr,DWORD_SIZE);
         }
      }
      if (changeFlag)
         MemSetVerifyWrites(origVerifyFlag);

   }
   dirty = TRUE; // force re-display
   memcpy(bufferValue, newValueBuffer,fieldCnt);
   return err;
}

//-----------------------------------------------------------------------------
// IsWatched
//-----------------------------------------------------------------------------
BOOLEAN TRegister::IsWatched() { return watched; }

//-----------------------------------------------------------------------------
// SetWatch
//-----------------------------------------------------------------------------
VOID TRegister::SetWatch(BOOLEAN watchMode) { watched = watchMode; }

//-----------------------------------------------------------------------------
// GetViewMode
//-----------------------------------------------------------------------------
TRegister::VIEWMODE TRegister::GetViewMode() { return view; }

//-----------------------------------------------------------------------------
// SetViewMode
//-----------------------------------------------------------------------------
VOID TRegister::SetViewMode(VIEWMODE viewMode) { view = viewMode; }

//-----------------------------------------------------------------------------
// AddFieldInfo
//-----------------------------------------------------------------------------
VOID TRegister::AddFieldInfo(Object& field) { fieldInfo.addAtTail(field); }

//-----------------------------------------------------------------------------
// GetFieldInfo
//-----------------------------------------------------------------------------
PTField TRegister::GetFieldInfo(U32 index) {
    U32 numItems;
    ContainerIterator& next = fieldInfo.initIterator();
    numItems = fieldInfo.getItemsInContainer();
    if (numItems == 0) return (NULL);
    if (index > (numItems - 1))
       return ((PTField)(&((TField&)fieldInfo.peekAtTail())));
    else {
       for (; index > 0; index--,next++);
       return ((PTField)(&((TField&)next.current())));
    }
}

//-----------------------------------------------------------------------------
// SetFieldValues
//-----------------------------------------------------------------------------
VOID TRegister::SetFieldValues() { 
   U16 i;
   PTField field = NULL;
   U32 regVal;
   U32 fieldVal;

   regVal = value.GetValue(); 
   for (i = 0; i < fieldCnt; i++) {
      field = GetFieldInfo(i);
      if (field == NULL || *field == NOOBJECT) continue; // firewall
      fieldVal = field->MaskOutValue(regVal,GetSize());
      field->SetValue(fieldVal);
   }
}

//-----------------------------------------------------------------------------
// GetFormatValue
//-----------------------------------------------------------------------------
S16 TRegister::GetFormatValue(LPSTR valueStr) {
   // do not format buffer
   if (buffer || !valueStr)
      return 0;

   switch (size) {
      case 1:
         return ((status == GOOD) ?
                 sprintf(valueStr, "%2.2lX", GetValue()) :
                 sprintf(valueStr, "??"));
      case 2:
         return ((status == GOOD) ?
                sprintf(valueStr,"%4.4lX", GetValue()) :
                sprintf(valueStr, "????"));
      case 4:
         return ((status == GOOD) ?
                sprintf(valueStr,"%8.8lX", GetValue()) :
                sprintf(valueStr,"????????"));
   }  
   return 0;
}


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