/****************************************************************************
**
**  Name:  treg.cpp
**
**  Description:
**     Source file for peripheral server treg component.
**
**  $Log:   S:/tbird/mt2_186/peri/treg.cpv  $
** 
**    Rev 1.2   29 Jul 1998 12:08:00   hera
** Fixed bug of showing the register's value in peripher window.
** 
**    Rev 1.1   27 Mar 1998 13:25:16   Winky
** modify formateregister()
** 
**    Rev 1.0   16 Dec 1996 16:19:38   Judy
** Initial revision.
** 
**    Rev 1.0   11 Oct 1996 18:47:16   Judy
** Initial revision.
** 
**    Rev 1.29   11 Oct 1994 09:22:44   dennis
** Added code to support 386ex.
** 
**    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/mt2_186/peri/treg.cpv   1.2   29 Jul 1998 12:08:00   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;
   extended     = 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 = strtol(lpTok, &endptr, 0);
   if (lTmp < 0) return;
   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 extended only flag (for Intel only)
   if (errField == 9)
      errField = 10;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok != NULL) {
      uTmp = strtoul(lpTok, &endptr, 0);
      extended = (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;

   // Set the default value
   uTmp = 0;
   if (noReads)
      uTmp = GetDefaultValue(); 
   value.SetValue(uTmp);
   SetFieldValues();

   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
//-----------------------------------------------------------------------------
RETCODE TRegister::FormatRegister(LPSTR text) {
   S8 regAddr[32];
   S8 value[32];
   S8 desc[MAX_INFOSTR];
   DESCRIPTOR tmpDesc = NULL;

   regAddr[0] = '\0';
   value[0] = '\0';
   desc[0] = '\0';
   text[0] = '\0';
   
   // Get the display address
   if ((status = PeriServer->GetRegisterAddress(this,&tmpDesc)) != GOOD) {
      if (tmpDesc != NULL) AdrDestroyAddress(tmpDesc);
      return status;
   }

   // 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 ((status = AdrConvAddressToTextWithParams(tmpDesc,FALSE,FALSE, regAddr)) 
      != GOOD) {
      if (tmpDesc != NULL) AdrDestroyAddress(tmpDesc);      
      return status;
   }

   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 the register is in-accessible but we are displaying
   // it anyway, place a "?" character at the beginning.
   /*if (!valid)
      strcat(text,"?");
   else --Hera 3/27/98*/
   strcat(text," ");
   //Hera 3/27/98
   if(strlen(regAddr) == 3)
      strcat(text,"00");
   regAddr[strlen(regAddr)-1] = '\0';
   //Hera
   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;
   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);
         sprintf(text,"\t%lu:\t  %lX\t%Fs", (U32) field->GetFieldLocation(), 
                 (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);
            if (!PeriServer->IsIntel())
               tmpU16 = MemSwapBytesInWord(tmpU16);
            sprintf(statTempVal,"%4.4lX ", (U32) tmpU16);
            break;
         case 4:
            tmpU32 = *((U32 *) tmpBufPtr);
            if (!PeriServer->IsIntel())
               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; 
}

//-----------------------------------------------------------------------------
// IsExtended
//-----------------------------------------------------------------------------
BOOLEAN TRegister::IsExtended() { 
   return extended; 
}

//-----------------------------------------------------------------------------
// GetValue
//-----------------------------------------------------------------------------
U32 TRegister::GetValue() {
   // For write only registers, default register value to 0
   /* if (noReads)
      return(GetDefaultValue()); */ 
   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;
   PTGroup tmpGroup;
   PROBE_TYPE proc;
     
   if ((err = ProcReturnSpecificProcessor(&proc)) != GOOD)
      return(err);

   if (((proc & I80C186_FAMILY) == I80C186_FAMILY) ||
            ((proc & A80186_FAMILY) == A80186_FAMILY)) {
      if (GetWritePermission()) {
         if (address) {
            tmpGroup = PeriServer->GetGroupInfo(GetGroupId());
            offset16 = (U16)(GetAddrOffset() & 0xFFFF)+
                       (U16)(tmpGroup->GetBaseOffset() & 0xFFFF) ;
            //if (stricmp(tmpGroup->GetName(buf), "SYS") == 0) {
            //   if (PeriServer->HasMBAR() && stricmp("MBAR", name) == 0) {
            //      addrMBAR = (newValue & 0x0FFF) << 12;
            //      if ((err=SdnWriteMember(SDN_SIM_ADDRESS, (U8 FAR *)&addrMBAR,
            //           GOOD)) != GOOD) return(err);
            //   }
            //   relative = FALSE;
            //}
            if ((err = Sds2AbiSetInternalReg(offset16,newValue)) != GOOD)
               return(err);

            if ((err = PeriInvalidateDisplay()) != GOOD)
               return(err);
         }
         if (err != GOOD)
            dirty = TRUE;
         else {
            value.SetValue(newValue);
            SetFieldValues();
            dirty = FALSE;
         }
      }
   } else {
     // write to memory if address is valid
     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;
           if (PeriServer->IsIntel())
              PeriServer->SetReMap();
           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);
                 if (!PeriServer->IsIntel())
                    tmpValueW = MemSwapBytesInWord(tmpValueW);
                 *((U32 *)memBufferPtr) = tmpValueW;
                 err = MemWriteSized(address,size,memBufferPtr,WORD_SIZE);
                 break;
              case DWORD_SIZE:
                 tmpValueDW = (U32) (newValue & unusedBitMask);
                 if (!PeriServer->IsIntel())
                    tmpValueDW = MemSwapBytesInLong(tmpValueDW);
                 *((U32 *)memBufferPtr) = tmpValueDW;
                 err = MemWriteSized(address,size,memBufferPtr,DWORD_SIZE);
                 break;
           }
           if (PeriServer->IsIntel())
              PeriServer->ResetReMap();
           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;
   U16 offset16;
   PROBE_TYPE proc;
   PTGroup tmpGroup;

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

   if (newValueBuffer == NULL)
      return ER_PP_INVALID_VALUE;

   if ((proc & I80C186_FAMILY) == I80C186_FAMILY) {
      if (GetWritePermission())
         if (address) {
            S8 buf[32];
            tmpGroup = PeriServer->GetGroupInfo(GetGroupId());
            offset16 = (U16)(GetAddrOffset() & 0xFFFF)+
                       (U16)(tmpGroup->GetBaseOffset() & 0xFFFF) ;
            //if (stricmp(tmpGroup->GetName(buf), "SYS") == 0) {
            //   if (PeriServer->HasMBAR() && stricmp("MBAR", name) == 0) {
            //      addrMBAR = ((U32)(*newValueBuffer) & 0x0FFF) << 12;
            //      if ((err=SdnWriteMember(SDN_SIM_ADDRESS, (U8 FAR *)&addrMBAR,
            //           GOOD)) != GOOD) return(err);
            //   }
            //   relative = FALSE;
            //}
            if ((err = Sds2AbiSetInternalReg(offset16,(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);
        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);
        }
     } 
     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);
      field->SetValue(fieldVal);
   }
}

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

   for (i = 0; i < fieldCnt; i++) {
      field = GetFieldInfo(i);
      if (field == NULL || *field == NOOBJECT) continue; // firewall
      fieldVal = field->MaskOutValue(regVal);
      if ((fieldVal < field->GetMinValue()) ||
         (fieldVal > field->GetMaxValue()))
         return(TRUE);
   }
   return(FALSE);
}

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

   regVal = 0L; 
   for (i = 0; i < fieldCnt; i++) {
      field = GetFieldInfo(i);
      if (field == NULL || *field == NOOBJECT) continue; // firewall
      minVal = field->GetMinValue();
      if ((minVal == field->GetMaxValue()) || (minVal != 0L)) {
         fieldVal = field->ShiftValue(minVal);
         regVal |= fieldVal;
      }
   }
   return(regVal);
}

//-----------------------------------------------------------------------------
// 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 **********************************/
