/****************************************************************************
**
**  Name:  CPUTAB.C
**
**  Description:
**     CPU table read routines.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/arcppc/cpu/cputab.c_v  $
** 
**    Rev 1.9   03 Feb 1998 15:07:30   kevin
** initialize selection flags whenever dialog box of sel reg is opened.
** 
**    Rev 1.8   11 Dec 1997 16:18:58   kevin
** If the viewable register doesn't have corresponding stock register, SLD will
** lose control. Fixed
** 
**    Rev 1.7   03 Dec 1997 14:15:40   kevin
** fixed a typo error
** 
**    Rev 1.6   03 Dec 1997 11:07:04   kevin
** Build stock registers while initialization
** 
**    Rev 1.5   19 Aug 1997 15:55:34   cjchen
** 
**    Rev 1.4   18 Jul 1997 17:55:08   cjchen
** 
**    Rev 1.3   30 Jun 1997 15:59:24   kevin
** added a dialog box for changing view order
** 
**    Rev 1.2   11 Mar 1997 18:02:56   kevin
** fixed a problem of getstockregnames()
** 
**    Rev 1.1   11 Feb 1997 11:37:04   kevin
** PowerPC
** 
**    Rev 1.0   17 Jan 1997 09:12:10   kevin
** Initial revision.
** 
**    Rev 1.0   03 Jun 1996 11:16:52   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:10:44   gene
** Initial revision.
** 
**    Rev 1.7   16 Jul 1993 11:49:14   ernie
** Removed error.h include.  All errors now in errcodec.h
** 
**    Rev 1.6   13 Jul 1993 19:16:08   doug
** Change error name to avoid conflict with other module
** 
**    Rev 1.5   30 Jun 1993 10:21:34   steveh
** Changed CPU_NO to NO_CPU
** 
**    Rev 1.4   31 Mar 1993 13:41:32   ernie
** 1. Changed logic to avoid hardcoding configuration file names.  Now
**    calls ProcInsertCpu() to create a filename of the form "cpu%s.cfg",
**    where %s is replaced by the cpu name ("cpu16" or "cpu32").  This
**    avoids changes to this file when new cpu families are implemented.
** 2. Changed logic for displaying error when the configuration file
**    cannot be opened.  Now uses ErrDisplayString() so that the filename
**    is part of the error message.
** 
**    Rev 1.3   30 Mar 1993 08:32:14   ernie
** 1. Heavy cleanup to conform to Microtek coding standards.
** 2. Changed format and name of config file to allow generic presenter.
** 
**    Rev 1.2   31 Jul 1992 09:39:12   doug
** change name of configuration file to be consistent with others
** 
**    Rev 1.1   21 Jul 1992 08:12:50   doug
** a) no aliases
** b) removed nitems to get rid of warning
** 
**    Rev 1.0   14 Jul 1992 12:18:28   courtney
** Initial revision.
** 
**  $Header:   S:/tbird/arcppc/cpu/cputab.c_v   1.9   03 Feb 1998 15:07:30   kevin  $
**
**  Copyright (C) 1992 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <stdio.h>
#include <string.h>
#ifndef _CPU_
#include "cpu.h"        /* CPU Server */
#endif
#ifndef _CPUCLI_
#include "cpucli.h"     /* CPU Server cli and Internal data structures */
#endif
#ifndef _CPURC_
#include "cpurc.h"
#endif
#ifndef _CPUERR_
#include "cpuerr.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif
#ifndef _PROC_
#include "proc.h"
#endif
#ifndef _EVENTS_
#include "events.h"
#endif
#ifndef _ENLIB_
#include "enlib.h"
#endif
#ifndef _SDPROBE_
#include "sdprobe.h"
#endif

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

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


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

RETCODE PRIVATE BuildRegTable(VOID);
RETCODE PRIVATE BuildSignalTable(VOID);
RETCODE PRIVATE InitSelRegDlg(HWND hDlg);
RETCODE PRIVATE SaveConfig(HWND hDlg);
RETCODE PRIVATE MoveItems(HWND hDlg, BOOL bAdd);
RETCODE PRIVATE SelAllRegs(HWND hDlg, S16 item, BOOL *bSel);
BOOL EXPORT CpuViewOrderDlgProc(HWND, WORD, WORD, LONG);

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


#define PATHLEN  128  /* Dos specific */
#define MAX_LINE  80

#define MAX_CPU_REGISTERS  0x3f  /* max 64 supported by firmware */
#define MAX_CPU_SIGNALS    0x0f  /* max 16 signals supported by firmware */

typedef S8 REGLIST[MAX_REGNAME];

U16 nTotalRegs;

static FILE *ifp;  /* cpu configuration file */
static S8 cline[MAX_LINE];
static U16 nViewRegs;
static REGLIST* viewRegs;
					/****************************
					*                           *
					*    EXTERNAL VARIABLES     *
					*                           *
					****************************/

extern REGISTER_ENTRY *regTable;
extern SIGNAL_ENTRY *signalTable;
extern REGNAME *stockRegName;
extern U16 nRegisters;
extern U16 nSignals;
extern REG_ID regSP;
extern HANDLE hLib;
extern STOCK_REGISTER *pStockReg;
					/****************************
					*                           *
					*      EXECUTABLE CODE      *
					*                           *
					*****************************/


RETCODE EXPORT BuildTables(BOOL bRebuild) {
   RETCODE err;
   S8 cpuConfigFilename[32];

   if ((err = ProcInsertCpu("cpu%s.cfg",cpuConfigFilename)) != GOOD)
       return(err);

   if ((ifp = fopen(cpuConfigFilename, "r")) == NULL) {
      err = ER_NO_CPU_CONFIG_FILE;
      ErrDisplayString(err, cpuConfigFilename, FORCE_POPUP);
      return (err);
   }

   if (bRebuild) TFree((LPSTR) regTable);
   if ((err = BuildRegTable()) != GOOD) {
      fclose(ifp);
      nRegisters=0;
      return (err);
   }

   if (!bRebuild && (err = BuildSignalTable()) != GOOD) {
      fclose(ifp);
      nSignals=0;
      return (err);
   }
   fclose(ifp);
   return (GOOD);
}  /* BuildTables */

/* see _BuildXlate in lxlate.c */
RETCODE PRIVATE BuildRegTable(VOID) {
    static char rname[10];  /* register name */
    U16 rsize, nFlags, line, rOrder;
    S16 i;  /* register index */
    static char item[20];
    U16 nsize;
    U32 value;

    /* skip ahead to nRegs line in config file */
    do {
       if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    } while (strstr(cline, "nTotalRegs") == NULL);
    
    /* read in number of stock registers */
    sscanf(cline, "%10s = %d", item, &nTotalRegs);
    /* read information of each register */
    nsize = nTotalRegs * sizeof(STOCK_REGISTER);
    if ((pStockReg = (STOCK_REGISTER *)TMalloc(nsize)) == NULL)
        return (ER_NO_MEM);
    /*
    ** Register table format:
    **   register name
    **   number of bits
    **   type of display (0=hex, 1=flags)
    **   Stock order
    */ 
    for (i=0; i<nTotalRegs; i++) {
        if (fgets(cline, MAX_LINE, ifp) == NULL)
           return(ER_CPU_CONFIG_FILE_FORMAT);
        if (sscanf(cline, "%10s %d %d %d", rname, &rsize, &nFlags, &rOrder) != 4)
           return(ER_CPU_CONFIG_FILE_FORMAT);
        pStockReg[i].order = rOrder;
        strcpy(pStockReg[i].regName, rname);
        if (sprintf(pStockReg[i].allInfo, "%-10s %2d %2d %3d", rname, rsize,
           nFlags, rOrder) < 0) return(ER_CPU_CONFIG_FILE_FORMAT);
    }

    /* skip ahead to nRegs line in config file */
    do {
       if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    } while (strstr(cline, "nRegs") == NULL);
    
    /* read in number of registers */
    sscanf(cline, "%5s = %d", item, &nRegisters);
    if (nRegisters > MAX_CPU_REGISTERS) nRegisters = MAX_CPU_REGISTERS;

    nsize = nRegisters*sizeof(REGISTER_ENTRY);
    if ((regTable = (REGISTER_ENTRY *)TMalloc(nsize)) == NULL)
        return (ER_NO_MEM);

    /*
    ** Register table format:
    **   register name
    **   number of bits
    **   type of display (0=hex, 1=flags)
    **   line number in cpu presenter window (top line is 0)
    */ 
    for (i=0; i<nRegisters; i++) {
        if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
        if (sscanf(cline, "%10s %d %d %d %d", rname, &rsize, &nFlags,
           &rOrder, &line) != 5) return(ER_CPU_CONFIG_FILE_FORMAT);
        strcpy(regTable[i].regName, rname);
        regTable[i].regWidth = rsize;
        regTable[i].numberOfFlags = min(32,nFlags);
        regTable[i].fwRegOrder = rOrder;
        regTable[i].presenterLine = line;
        regTable[i].flagTable = NULL;
    }

    /*
    ** For each register indicated as displayAsFlags, find the flag bit
    ** description in the file and load into that register's flagTable.
    */
    for (i=0; i<nRegisters; i++) if (regTable[i].numberOfFlags > 0) {
       U16 field,aChar,nChar,type,shift;
       U32 mask;
       do {
          if (fgets(cline, MAX_LINE, ifp) == NULL)
             return(ER_CPU_CONFIG_FILE_FORMAT);
       } while (strstr(cline, regTable[i].regName) == NULL);

       nsize = nRegisters*sizeof(REGISTER_ENTRY);
       if ((regTable[i].flagTable = (FLAG_TABLE *)
              TMalloc(regTable[i].numberOfFlags*sizeof(FLAG_TABLE))) == NULL)
          return (ER_NO_MEM);
       for (field=0; field<regTable[i].numberOfFlags; field++) {
          if (fgets(cline, MAX_LINE, ifp) == NULL)
             return(ER_CPU_CONFIG_FILE_FORMAT);
          if (sscanf(cline, "%c %c %d %lx", &aChar, &nChar, &type, &mask) != 4)
             return(ER_CPU_CONFIG_FILE_FORMAT);
          regTable[i].flagTable[field].assertedChar = aChar;
          regTable[i].flagTable[field].negatedChar = nChar;
          regTable[i].flagTable[field].displayAsChar = (type == 1);
          regTable[i].flagTable[field].mask = mask;
          for (shift=0; (mask&1L)==0; shift++) mask>>=1;  /*find lsb of field*/
          regTable[i].flagTable[field].shift = shift;
       }
    }
    //get reg value from fw
    //for (i=0; i<nRegisters; i++)
    //    GetReg(regTable[i].fwRegOrder,&value);
    Sds2AbiFwUnloadRegisters(FALSE);

    return(GOOD);
}  /* BuildRegTable */

RETCODE PRIVATE BuildSignalTable(VOID) {
    static char sname[10];  /* signal name */
    S16 i;  /* signal index */
    static char item[20];
    U16 nsize;
    char *ret;

    /* fill signalTable from values in cpu configuration file */
    /* read in nSignals from first item in cpucfg.xxx file */
    while ((ret = fgets(cline, MAX_LINE, ifp)) != NULL) {
        if (strstr(cline, "nSigs") != NULL)
            break;
    }
    if (ret == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);

    sscanf(cline, "%5s = %d", item, &nSignals);
    if (nSignals == 0) return(GOOD);
    /* check value for validity */
    if (nSignals > MAX_CPU_SIGNALS)
        nSignals = MAX_CPU_SIGNALS;

    nsize = nRegisters*sizeof(SIGNAL_ENTRY);
    if ((signalTable = (SIGNAL_ENTRY *)TMalloc(nsize)) == NULL)
        return (ER_NO_MEM);

    i = 0;
    while ((ret = fgets(cline, MAX_LINE, ifp)) != NULL) {
        if (sscanf(cline, "%10s", sname) != 1)
            continue;
        strcpy(signalTable[i].signalName, sname);
        signalTable[i++].sdDesc = NULL;
        if (i == nSignals)
            break;
    }
    if (ret == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    return (GOOD);

}  /* BuildSignalTable */

/******************************************************
**
**   CpuSelRegDlgProc
**
** The dialog window procedure
**
**  returns result to DialogBox callerwith EndDialog() function::
**    TRUE:   user pressed OK
**    FALSE:  user pressed cancel
**
**  After pressing OK, if parse is not successful (or
**  some other error occurs), we display the error, and
**  permit a retry.  User can exit with Cancel, though.
**
**  Note that errors are NOT propagated up to Actor level.
**
**
**  The params follow Windows 3.0 conventions, NOT those of Win3.1
**
**  Return value is standard also: a Windows BOOL, NOT the
**  Powerviews BOOLEAN!
**  returns TRUE of message was handled, FALSE if not handled.
**
*******************************************************/
#pragma argsused
BOOL EXPORT CpuSelRegDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam) {
   static BOOL bStockSel, bViewSel;
   S8  i;
   RETCODE err;

   switch (message)
   {
      case WM_INITDIALOG:
         if (InitSelRegDlg(hDlg) != GOOD) {
            MessageBox(hDlg,"The config file is corrupted", 
                 NULL, MB_ICONEXCLAMATION|MB_OK);
            PostMessage(hDlg, WM_COMMAND, IDCANCEL, NULL);
         }
         bStockSel = bViewSel = FALSE;
         return TRUE;

//      case WM_DESTROY:
//           ifp = NULL;
//           TFree((LPSTR) pStockReg);
//           return TRUE;

      case WM_COMMAND:
         switch(wParam) {
            case IDC_B_ADD:
               MoveItems(hDlg, TRUE);
               break;
            case IDC_B_REMOVE:
               MoveItems(hDlg, FALSE);
               break;
            case IDC_B_SELALLSTOCK:
               SelAllRegs(hDlg, IDC_LB_UNSELREG, &bStockSel);
               SetWindowText(GetDlgItem(hDlg, IDC_B_SELALLSTOCK),
                     (bStockSel ? "< Unsel All": "< Sel All"));
               break;
            case IDC_B_SELALLVIEW:
               SelAllRegs(hDlg, IDC_LB_SELREG, &bViewSel);
               SetWindowText(GetDlgItem(hDlg, IDC_B_SELALLVIEW),
                     (bViewSel ? "Unsel All >": "Sel All >"));
               break;
            case IDC_B_VIEWORDER:
               nViewRegs = (S16)SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_GETCOUNT, NULL, NULL);
               if ((viewRegs = (REGLIST *)TMalloc(nViewRegs * sizeof(REGLIST)))
                  == NULL) return (ER_NO_MEM);

               for (i=0; i<nViewRegs; i++) {
                  SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_GETTEXT, (WORD)i,
                     (LONG)viewRegs[i]);
               }
               if (DialogBox(hLib, "CPU_VIEWORDER_DLG", hDlg,
                  CpuViewOrderDlgProc) == TRUE) {
                  SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_RESETCONTENT, 0, 0);

                  for (i=0; i<nViewRegs; i++)
                     SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_ADDSTRING, NULL,
                        (LONG)viewRegs[i]);
               }

               TFree(viewRegs);
               break;
            case IDOK:
               if ((err = SaveConfig(hDlg)) != GOOD)
                  ErrDisplayError(err,FORCE_POPUP);
               EndDialog(hDlg, TRUE);
               BuildTables(TRUE);
               err = EnlEventNotify(EVENT_TRACE_CLEAR_TRACE);
               /*
               MessageBox(hDlg,
                 "The setting will take effect after reopening the CPU window",
                 NULL, MB_ICONEXCLAMATION|MB_OK);
               */
               return TRUE;

//          case IDHELP:
//             WinHelp(hDlg, "PWRVIEWS.HLP", HELP_CONTEXT, 044); // entry for mem help
//             return FALSE;

            case IDCANCEL:
               EndDialog(hDlg, FALSE);
               return TRUE;
         }
   }
   return (FALSE);   // Didn't process a message
}

/******************************************************
**
** CpuDlgSelReg   Select register dialog box
**
**   Execute the dialog
**
**  called from ACTOR memory presenter menu item...
**
*******************************************************/

RETCODE EXPORT CpuDlgSelReg(HWND hWnd)   {
   int      dlgRet;

   dlgRet = DialogBox(hLib,           // instance (for dlg template)
            "CPU_SELREG_DLG",
            hWnd,                     // parent handle
            CpuSelRegDlgProc);  // within DLL, no proc instance address reqd


// if user pressed OK, perform the copy
// using the native (parsed) form.
   if (dlgRet == TRUE)  {

   }

   return GOOD;
}

RETCODE PRIVATE InitSelRegDlg(HWND hDlg) {
   VIEW_REGISTER* pViewReg;
   char rname[MAX_REGNAME];  /* register name */
   U16 rsize, nFlags, line, rOrder, nViewRegs;
   S16 i;  /* register index */
   static char item[20];
   U16 nsize;
   RETCODE err;
   S8 cpuConfigFilename[32];

   if ((err = ProcInsertCpu("cpu%s.cfg",cpuConfigFilename)) != GOOD)
       return(err);

   if ((ifp = fopen(cpuConfigFilename, "r")) == NULL) {
      err = ER_NO_CPU_CONFIG_FILE;
      ErrDisplayString(err, cpuConfigFilename, FORCE_POPUP);
      return (err);
   }

//////////////  get info of stock registers //////////////
    /* skip ahead to nRegs line in config file */
    do {
       if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    } while (strstr(cline, "nTotalRegs") == NULL);


//////////////  get info of viewable registers //////////////
    /* skip ahead to nRegs line in config file */
    do {
       if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    } while (strstr(cline, "nRegs") == NULL);
    
    /* read in number of registers */
    sscanf(cline, "%5s = %d", item, &nViewRegs);

   /** Register table format:
    **   register name
    **   number of bits
    **   type of display (0=hex, 1=flags)
    **   line number in cpu presenter window (top line is 0)
    */

    nsize = nViewRegs * sizeof(VIEW_REGISTER);
    if ((pViewReg = (VIEW_REGISTER *)TMalloc(nsize)) == NULL)
        return (ER_NO_MEM);
    for (i=0; i<nViewRegs; i++) {
        if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
        if (sscanf(cline, "%10s %d %d %d %d", rname, &rsize, &nFlags,
           &rOrder, &line) != 5) return(ER_CPU_CONFIG_FILE_FORMAT);
        pViewReg[i].regId = rOrder;
        pViewReg[i].order = line;
    }
    for (i=0; i<nViewRegs; i++) {
       U8  j=0,k=0;
       while (pViewReg[j].order != i && j < nViewRegs) j++;
       if (j == nViewRegs)
          return(ER_CPU_CONFIG_FILE_FORMAT);
       while (pViewReg[j].regId!=pStockReg[k].order) {
          if (++k > nTotalRegs) // something wrong in config file, could not find a match stock register
             return(ER_CPU_CONFIG_FILE_FORMAT);
       }
       SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_ADDSTRING, NULL,
          (LONG)pStockReg[k].regName);
    }

    for (i=0; i<nTotalRegs; i++) {
       U8  j=0;
       while (pViewReg[j].regId != pStockReg[i].order && j < nViewRegs) j++;
       if (j == nViewRegs)
          SendDlgItemMessage(hDlg, IDC_LB_UNSELREG, LB_ADDSTRING, NULL,
                (LONG)pStockReg[i].regName);
    }

    TFree((LPSTR) pViewReg);
    fclose(ifp);
    return(GOOD);
}  /* BuildRegTable */

RETCODE PRIVATE SaveConfig(HWND hDlg) {
   FILE* ofp;
   S16 i;
   S16 nRegs;
   S8 cpuConfigFilename[32];
   RETCODE err;

   if ((err = ProcInsertCpu("cpu%s.cfg",cpuConfigFilename)) != GOOD)
       return(err);

   if ((ifp = fopen(cpuConfigFilename, "r")) == NULL ||
       (ofp = fopen("~~cpu~~.~~~", "w")) == NULL) {
      err = ER_NO_CPU_CONFIG_FILE;
      ErrDisplayString(err, cpuConfigFilename, FORCE_POPUP);
      return (err);
   }

   while (fgets(cline, MAX_LINE, ifp) != NULL &&
          strstr(cline, "nRegs") == NULL) {
      if (fputs(cline, ofp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
   }

   nRegs = (S16)SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_GETCOUNT, NULL, NULL);

   /* read in number of registers */
   sprintf(cline, "nRegs = %d\n", nRegs);
   if (fputs(cline, ofp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);

   for (i=0; i<nRegs; i++) {
      U16 j=0;
      REGNAME regName;

      SendDlgItemMessage(hDlg, IDC_LB_SELREG, LB_GETTEXT, (WORD)i, (LONG)regName);
      while (stricmp(regName, pStockReg[j].regName) != NULL && ++j < nTotalRegs);
      if (j == nTotalRegs)
         return(ER_CPU_CONFIG_FILE_FORMAT);

      sprintf(cline, "%s %2d\n", pStockReg[j].allInfo, i);
      if (fputs(cline, ofp) == NULL)
         return(ER_CPU_CONFIG_FILE_FORMAT);
   }
   strcpy(cline, " \n");
   if (fputs(cline, ofp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
   /* skip register definition*/
   do {
      if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
   } while (strstr(cline, "!!!!") == NULL);

   do {
      if (fputs(cline, ofp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
   } while (fgets(cline, MAX_LINE, ifp) != NULL);

   fclose(ifp);
   fclose(ofp);

   remove("~~cpu~~.bak");
   if (rename(cpuConfigFilename, "~~cpu~~.bak") != GOOD ||
       rename("~~cpu~~.~~~", cpuConfigFilename) != GOOD) {
      remove("~~cpu~~.~~~");
      rename("~~cpu~~.bak", cpuConfigFilename);
      return(ER_CPU_CONFIG_FILE_FORMAT);
   }

   return(GOOD);
}

RETCODE PRIVATE SelAllRegs(HWND hDlg, S16 item, BOOL *bSel) {
   S16 nRegs;

   *bSel = !*bSel;
   nRegs = (S16)SendDlgItemMessage(hDlg, item, LB_GETCOUNT, NULL, NULL);
   SendDlgItemMessage(hDlg, item, LB_SELITEMRANGE, *bSel, (LONG)nRegs-1);

   return(GOOD);
}

RETCODE PRIVATE MoveItems(HWND hDlg, BOOL bAdd) {
   U16  target, source;
   S16  nRegs, nCount, i;
   S16* pSelItem;
   REGNAME regName;

   source = bAdd ? IDC_LB_UNSELREG: IDC_LB_SELREG;
   target = bAdd ? IDC_LB_SELREG  : IDC_LB_UNSELREG;

   if ((nCount=(S16)SendDlgItemMessage(hDlg,source,LB_GETSELCOUNT,
         NULL,NULL)) == 0) return(GOOD);

   nRegs = (S16)SendDlgItemMessage(hDlg, target, LB_GETCOUNT, NULL, NULL);
   if (bAdd && (nRegs+nCount) > MAX_CPU_REGISTERS) {
      MessageBox(hDlg, "Too many selection", NULL, MB_ICONEXCLAMATION|MB_OK);
      return(GOOD); //!! error
   }

   pSelItem = (S16*) TMalloc(sizeof(S16)*nCount);
   SendDlgItemMessage(hDlg, source, LB_GETSELITEMS, nCount, (LONG)pSelItem);

   for (i=0; i<nCount; i++) {
      SendDlgItemMessage(hDlg, source, LB_GETTEXT, (WORD)pSelItem[i],
            (LONG)regName);
      if (strcmp(regName,"SRR0")==0 ||
          strcmp(regName,"GPR01")==0 ||
          strcmp(regName,"LR")==0) {
          MessageBox(hDlg, "Can't remove SRR0, GPR01, or LR register",NULL, MB_ICONEXCLAMATION|MB_OK);
          return GOOD;
       }
   }

   for (i=0; i<nCount; i++) {
      SendDlgItemMessage(hDlg, source, LB_GETTEXT, (WORD)pSelItem[i],
            (LONG)regName);
      SendDlgItemMessage(hDlg, target, LB_ADDSTRING, NULL, (LONG)regName);
   }

   for (i=nCount-1; i>=0; i--)
      SendDlgItemMessage(hDlg, source, LB_DELETESTRING, (WORD)pSelItem[i],
            NULL);

   TFree((LPSTR) pSelItem);
   return(GOOD);
}

RETCODE GetStockRegNames(U16* uNumReg) {
   REGNAME rname;  /* register name */
   U16 rsize, nFlags, rOrder;
   S16 i;  /* register index */
   static char item[20];
   U16 nsize;
   RETCODE err;
   S8 cpuConfigFilename[32];

   if ((err = ProcInsertCpu("cpu%s.cfg",cpuConfigFilename)) != GOOD)
       return(err);

   if ((ifp = fopen(cpuConfigFilename, "r")) == NULL) {
      err = ER_NO_CPU_CONFIG_FILE;
      ErrDisplayString(err, cpuConfigFilename, FORCE_POPUP);
      return (err);
   }

//////////////  get info of stock registers //////////////
    /* skip ahead to nRegs line in config file */
    do {
       if (fgets(cline, MAX_LINE, ifp) == NULL) return(ER_CPU_CONFIG_FILE_FORMAT);
    } while (strstr(cline, "nTotalRegs") == NULL);
    
    /* read in number of registers */
    sscanf(cline, "%10s = %d", item, uNumReg);

    nsize = *uNumReg * sizeof(REGNAME);
    if ((stockRegName = (REGNAME *)TMalloc(nsize)) == NULL)
        return (ER_NO_MEM);

    /*
    ** Register table format:
    **   register name
    **   number of bits
    **   type of display (0=hex, 1=flags)
    **   Stock order
    */ 
    for (i=0; i < *uNumReg; i++) {
        if (fgets(cline, MAX_LINE, ifp) == NULL)
           return(ER_CPU_CONFIG_FILE_FORMAT);
        if (sscanf(cline, "%10s %d %d %d", rname, &rsize, &nFlags, &rOrder) != 4)
           return(ER_CPU_CONFIG_FILE_FORMAT);
        strcpy(stockRegName[i], rname);
    }

    fclose(ifp);
    return(GOOD);
}  /* BuildRegTable */

/******************************************************
**
**   CpuViewOrderDlgProc
**
*******************************************************/
#pragma argsused
BOOL EXPORT CpuViewOrderDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam) {
   S8 i, nNewOrder, nOldOrder;
   DWORD nCurSel;
   RETCODE err;

   switch (message)
   {
      case WM_INITDIALOG:
         for (i=3; i<nViewRegs; i++)
         SendDlgItemMessage(hDlg, IDC_LB_OLDORDER, LB_ADDSTRING, NULL,
                (LONG)viewRegs[i]);
         for (i=0;i<3;i++)
         SendDlgItemMessage(hDlg, IDC_LB_NEWORDER, LB_ADDSTRING, NULL,
                (LONG)viewRegs[i]);
         return TRUE;

      case WM_COMMAND:
         switch(wParam) {
            WORD    sourceLB, targetLB;
            REGNAME regName;

            case IDC_LB_OLDORDER:
            case IDC_LB_NEWORDER:
               sourceLB = wParam;
               targetLB = (wParam==IDC_LB_OLDORDER)
                           ? IDC_LB_NEWORDER: IDC_LB_OLDORDER;

               if (HIWORD(lParam) == LBN_SELCHANGE) {
                  if ((nCurSel=SendDlgItemMessage(hDlg, sourceLB,
                      LB_GETCURSEL, 0, 0)) == LB_ERR) break;
                  SendDlgItemMessage(hDlg, sourceLB, LB_GETTEXT, (WORD)nCurSel, (LONG)regName);
                  if ((nCurSel==0 || nCurSel==1 || nCurSel==2) &&
                      sourceLB==IDC_LB_NEWORDER) {
                     MessageBox(hDlg, "Can't change order of SRR0, GPR01, LR",NULL, MB_ICONEXCLAMATION|MB_OK);
                     return TRUE;
                  }
                  SendDlgItemMessage(hDlg, sourceLB, LB_DELETESTRING, (WORD)nCurSel, 0);
                  SendDlgItemMessage(hDlg, targetLB, LB_ADDSTRING, NULL, (LONG)regName);
               }
               break;
            case IDOK:
               nNewOrder = (S16)SendDlgItemMessage(hDlg, IDC_LB_NEWORDER,
                  LB_GETCOUNT, NULL, NULL);

               for (i=0; i<nNewOrder; i++) {
                  SendDlgItemMessage(hDlg, IDC_LB_NEWORDER, LB_GETTEXT, (WORD)i,
                     (LONG)viewRegs[i]);
               }

               nOldOrder = (S16)SendDlgItemMessage(hDlg, IDC_LB_OLDORDER,
                  LB_GETCOUNT, NULL, NULL);

               for (i=0; i<nOldOrder; i++) {
                  SendDlgItemMessage(hDlg, IDC_LB_OLDORDER, LB_GETTEXT, (WORD)i,
                     (LONG)viewRegs[i+nNewOrder]);
               }

               EndDialog(hDlg, TRUE);
               return TRUE;

            case IDCANCEL:
               EndDialog(hDlg, FALSE);
               return TRUE;
         }
   }
   return (FALSE);   // Didn't process a message
}

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