
/***************************************************************************
**
** File name : CPUSERVE.CPP
** Author:BRIGHT CHEN  ,  JOHN CHOW
** Description:
**
**
**    Finished date: 1995.9.1   V 0.1
**    UPDATE DATE  : 1995.9.8   V 0.1A
**                  Modify the void ResetCmd(int nArgc, char* pszArgv[]),
**                  because v0.1 don't support the string "P:xxxx" or
**                  "X:xxxx";
**                    1995.9.26  V 0.1B
**                  Modify BOOL CCpuServer::GetRegFromFile()
**                  to fix bug no.116
**
**    Copyright (C) 1995 Microtek International, Inc.
**    All Rights Reserved
**
****************************************************************************/

//////////////////////////////////////
//regserve.cpp
//Bright Cheng
//95/4
//////////////////////////////////////

///////////////////////////////NOTES//////////////////////////////
/********************************************************************
NOTES TO HOW TO ADD DIFFERENT:
STEP 1:
     ADD CPU NAME INT THE "enum CPU_MODULE_LIST " AREA LIKE OTHERS.
     PLEASE KEEP THE SEQUENCE OF THE CPU NAME AND AT SAME TIME THE
     ORDER MUST BE KEPT WITH THE ABI TABLE;
STEP 2:
     ADD REG TABLE IN THE END OF FILE LIKE OTHERS THOUGH THE ORDER
     OF REG TABLE IS NO USE.
     THE REG IN "enum COMMON_REG" AREA HAS NO NEED TO BE ADDED TO
     THE REG TABLE.
     THE REG SEQUENCE MUST BE KEPT WITH ABI TABLE.
STEP 3:
     UPDATE THE DAD REG TABLE AT THE SAME TIME, THIS MEANS THE EP-SLD
     MUST BE REBUILDED.
                                                       John.chow 95.8
*************************************************************************/

#include "stdafx.h"
#include "string.h"
#include "stdlib.h"

#include "abibase.h"
#include "cpucom.h"
#include "cpuserve.h"
#include "hosterrs.h"
#include "cpust.h"           
#include "mainfrm.h"

#define REG_STATUS 12
#define REG_PORTC  15

void GetCpuName(CString& strName);
extern BOOL GetCpuStatus(unsigned char & uchStatus);
//STATUS AbiSetRegNumber(UINT nCpuNumber);
extern STATUS AbiGetAllReg(WORD* );
extern STATUS AbiSetReg(WORD,WORD);
extern STATUS AbiReset(ADDR addr);
extern STATUS AbiGetCpuId(WORD *nCpuId);
extern STATUS AbiSetCpuId(WORD nSetCpuId, WORD *nGetCpuId);
extern STATUS AbiClrAllBp();
extern void DisplayErrorMessageBox(int);
int StrtoHex(unsigned char *InputStr,unsigned short *Output);//from dad
STATUS AbiSetCpuId(UINT nSetCpuId, UINT *nGetCpuId);
STATUS AbiGetTargetSupport(UINT *wCpuNum, UINT* wCpuType);

unsigned char gEPModule;//suport dad to define cpu
extern char szAppPath[];



static CCpuServer CpuSrv;

 CPUModule cpuModule =
      {
        "Single Chip",              //cpu name
        "PC",         0,     0  ,  0   ,
        "W",          1,     0  ,  1   ,
        "SFR",        2,     0  ,  2   ,
        "RTCC",       3,     0  ,  3   ,
        "STATUS",     4,     0  ,  4   ,
        "PORTA",        5,     0  ,  5   ,
        "PORTB",         6,     1  ,  0   ,
        "PORTC",         7,     1  ,  1   ,
        "OPTION",         8,     1  ,  2   ,
        "TRISA",         9,     1  ,  3   ,
        "TRISB",         10,    1  ,  4   ,
        "TRISC",         11,    1  ,  5   ,
        "SP0",         12,    1  ,  6   ,
        "SP1",         13,    1  ,  7   ,
        "",         14,    2  ,  0   ,
        "",         15,    2  ,  1   ,
        "",       16,    2  ,  2   ,
        "",       17,    2  ,  3   ,
        "",        18,    3  ,  0   ,
        "",        19,    3  ,  1   ,
        "",        20,    3  ,  2   ,
        "",        21,    3  ,  3   ,
        "",       22,    4  ,  0   ,
        "",      23,    4  ,  1   ,
        "",         24,    4  ,  2   ,
        "",         25,    4  ,  3   ,
        "",         26,    4  ,  4   ,
        "",         27,    4  ,  5   ,
        "",           28,    0  ,  0   ,
        "",           29,    0  ,  0   ,
        "",           30,    0  ,  0   ,
        "",           31,    0  ,  0   ,
        "",           32,    0  ,  0   ,
        "",           33,    0  ,  0   ,
        "",           34,    0  ,  0   ,
        "",           35,    0  ,  0   ,
        "",           36,    0  ,  0   ,
        "",           37,    0  ,  0   ,
        "",           38,    0  ,  0   ,
        "",           39,    0  ,  0   ,
        "",           40,    0  ,  0   ,
        "",           41,    0  ,  0   ,
        "",           42,    0  ,  0   ,
        "",           43,    0  ,  0   ,
        "",           44,    0  ,  0   ,
        "",           45,    0  ,  0   ,
        "",           46,    0  ,  0   ,
        "",           47,    0  ,  0   ,
        "",           48,    0  ,  0   ,
        "",           49,    0  ,  0   ,
        "",           50,    0  ,  0   ,
        "",           51,    0  ,  0   ,
        "",           52,    0  ,  0   ,
        "",           53,    0  ,  0   ,
        "",           54,    0  ,  0   ,
        "",           55,    0  ,  0   ,
        "",           56,    0  ,  0   ,
        "",           57,    0  ,  0   ,
        "",           58,    0  ,  0   ,
        "",           59,    0  ,  0   ,
        "",           60,    0  ,  0   ,
        "",           61,    0  ,  0   ,
        "",           62,    0  ,  0   ,
        "",           63,    0  ,  0   ,
        14,                    //MAX_REG
        2,                     //Stack
    };
               
REG_ID CpuIndexToID(int i)
{
    return cpuModule.RegNameID[i].ID;
}               

int CpuIDToIndex(REG_ID reg_id)
{
    for(int i=0;i<nMaxReg;i++)
        if(cpuModule.RegNameID[i].ID==reg_id)
          return i;
    return -1;    
}               

BOOL IsIDValid(REG_ID reg_id)
{
    for(int i=0;i<nMaxReg;i++)
    {
        if(cpuModule.RegNameID[i].ID==reg_id)
            return 1;
    }            
    return 0;
}    

               
//added by john 96.1 to support 320 trace list
UINT GetCpuId()
{ 
 return CpuSrv.GetCpuId();
 }

//notes:in this function anything needing initiation about cpu , dad
int InitCpu(int iRoger)
{
  return(CpuSrv.Initialize(iRoger));

}
                           
CPURegisterFileRange GetCpuRFileRange()
{
    return (CpuSrv.m_cpuRFileRange);
}

                           
void CpuShowOneRegToWnd(int reg_id)
{   
    CpuSrv.ShowOneRegToWnd(reg_id);
}

void CpuShowAllRegToWnd()
{
    unsigned char  uchStatus;
    GetCpuStatus(uchStatus);
    if(uchStatus==1){
        AfxMessageBox("Please Halt the CPU first !" ,MB_OK);
        return ;
    }   
    CpuSrv.ShowAllRegToWnd();
}

BOOL CpuSetRegfromWnd(int reg_id,UINT content)
{
    return(CpuSrv.SetRegfromWnd(reg_id,content));
}

BOOL CpuGetAllReg()
{
    CpuSrv.m_nErrorID = CpuSrv.GetAllReg();
    if(ICE_OK == CpuSrv.m_nErrorID)
        return(TRUE);
    else
    {
        CpuSrv.DisplayErrorMessageBox();
        return(FALSE);
    }
}
                 
BOOL IsRegisterValid(CString str)
{
   for(int i = 0;i < nMaxReg; i++)
   {   
       if(str == RegName[i])
       {
          return 1;
       }
   }
   return 0;       
}   
              
void RegisterCmd(int nArgc,char* pszArgv[])
{
REG_ID  reg_id;
UINT    regval;
char*   stop_at;

    unsigned char  uchStatus;
    GetCpuStatus(uchStatus);
    if(uchStatus==1){
        ShowLine("Please Halt the CPU first !");
        return ;
    }   

    if(1==nArgc)
        CpuSrv.ShowAllRegToShell();
    
    if(3==nArgc||2==nArgc)
    {
        CString str = strupr(pszArgv[1]);
        for(int i = 0;i < nMaxReg; i++)
        {
            if(str == RegName[i])
            {
                reg_id =CpuIndexToID(i);
                break;
            }
        }       
        if(2==nArgc) CpuSrv.ShowOneRegToShell(reg_id);
        else{
            regval = (UINT)strtoul(pszArgv[2],&stop_at,16);
            CpuSrv.SetRegfromShell(reg_id,regval);
        }   
    }
}

void ResetCmd(int nArgc, char* pszArgv[])
{    
char* stop_at;
WORD  addr;

//  unsigned char  uchStatus;
//    GetCpuStatus(uchStatus);
//    if(uchStatus==1){
//      ShowLine("Please Halt the CPU first !");
//      return;
//    }     

    switch(nArgc)
    {
        case 1:
            CpuSrv.ResetbyShell(GetLoadPC());
            break;
        case 2:
            char *tmpPoint;
            tmpPoint= (char *)(&(pszArgv[1][0]));
            if('X' == toupper(pszArgv[1][0]))
             {
              ShowLine("Syntax error???");
              return;
              }
            if('P' == toupper(pszArgv[1][0]))
              tmpPoint= (char *)(&(pszArgv[1][2]));
            addr = (WORD)strtoul(tmpPoint,&stop_at,16);
            CpuSrv.ResetbyShell(addr);
            break;
        default:
            ShowLine("Syntax error???");
    }
}

BOOL CpuReset(WORD addr)
{
    return(CpuSrv.ResetbyWnd(addr));
}



//ONLY USED FOR SHOWING REGS IN SHELL


void CCpuServer::ShowAllRegToShell()
{
    m_nErrorID = GetAllReg();
    if(ICE_OK == m_nErrorID)
    {
       ShowAllRegByArray();
    }                    
    else
     DisplayErrorMessage();
} //end of ::ShowAllRegToShell()
//edit by JOHN.CHOW 95.6

STATUS CCpuServer::GetAllReg()
{
    return(AbiGetAllReg((WORD*)&RegValue[0]));  
}
    

void CCpuServer::ShowOneRegToShell(REG_ID reg_id)
{
    char DisplayStr[20];
    if (!IsIDValid(reg_id))
    {
        ShowLine("This register does not exist.");
        return;
    }

//    ret = AbiGetReg(reg_id,&content);
    m_nErrorID = GetAllReg();

    if(ICE_OK == m_nErrorID)
    {
        int i=0;
        for(i=0;i<nMaxReg;i++)
        {
            if(cpuModule.RegNameID[i].ID==reg_id) break;
        }
        if(reg_id<9)
            wsprintf(DisplayStr,"%s = %04X",RegName[i],RegValue[reg_id]);
        else
            wsprintf(DisplayStr,"%s = %02X",RegName[i],RegValue[reg_id]);
        
        ShowLine(DisplayStr);
    }
    else
        DisplayErrorMessage();
}//end of ::ShowOneRegToShell()


void CCpuServer::ShowOneRegToWnd(REG_ID reg_id)
{
UINT RegVal;
    unsigned char  uchStatus;
    GetCpuStatus(uchStatus);
    if(uchStatus==1){
        AfxMessageBox("Please Halt the CPU first !" ,MB_OK);
        return ;
    }   

    if (!IsIDValid(reg_id))
    {
        ErrDisplayError(ER_PRE_REG_NOT_EXIST);
        return;
    }

    RegVal = RegValue[reg_id];
//    status = AbiGetReg(reg_id, &content);
    m_nErrorID = GetAllReg();

    if(ICE_OK == m_nErrorID)
    {
        if (RegVal!=RegValue[reg_id])
        {
//          REGISTER[reg_id] = *content;
//          RegValue[reg_id]= content;
            CpuShowRegValue(reg_id);
        }
    }
    else
        DisplayErrorMessageBox();
}
 
void CCpuServer::ShowAllRegToWnd()
{
int i;

    m_nErrorID = GetAllReg();

    if(ICE_OK == m_nErrorID)
    {
        for(i=0;i<nMaxReg;i++)
            CpuShowRegValue(i);
    }
    else
        DisplayErrorMessageBox();
}                          



BOOL CCpuServer::SetRegfromWnd(REG_ID reg_id, UINT content)
{
int i;
    unsigned char  uchStatus;
    GetCpuStatus(uchStatus);
    if(uchStatus==1){
        AfxMessageBox("Please Halt the CPU first !" ,MB_OK);
        return 1;
    }   
    if(!IsIDValid(reg_id)) return 0;
    if(reg_id>9)
        if(content> 0xff)
        {
            ErrDisplayError(ER_PRE_REG_VALUE_OVERFLOW);
            return(FALSE);
        }

    m_nErrorID = AbiSetReg(reg_id,content);

    if(ICE_OK == m_nErrorID)
    {
        if (content!=RegValue[reg_id])
        {
            RegValue[reg_id] = content;
            CpuShowRegValue(reg_id);
// if PSW changed, all R0-R7 value may be changed either.
/*          if(reg_id==REG_STATUS)
            {
                m_nErrorID = GetAllReg();
                if(ICE_OK == m_nErrorID)
                    for( i=6;i<14;i++)
                        CpuShowRegValue(i);
                else
                {
                    DisplayErrorMessageBox();
                    return(FALSE);
                }
            }
*/        }
        return(TRUE);
    }
    else
    {
        DisplayErrorMessageBox();
        return(FALSE);
    }
    return(TRUE);
}

void CCpuServer::SetRegfromShell(REG_ID reg_id, UINT content)
{
    if(!IsIDValid(reg_id)) return ;
    char DisplayStr[20];
    if(reg_id>9)
        if(content > 0xff)
        {
            ShowLine(" Error! Register value overflow ");
            return;
        }

    m_nErrorID = AbiSetReg(reg_id,content);

    if(ICE_OK == m_nErrorID)
    {   
        m_nErrorID = GetAllReg();
        if(ICE_OK == m_nErrorID)
        {        
        if(reg_id<9)
            wsprintf(DisplayStr,"%s = %04X",RegName[reg_id],RegValue[reg_id]);
        else
            wsprintf(DisplayStr,"%s = %02X",RegName[reg_id],RegValue[reg_id]);
        ShowLine(DisplayStr);
        CpuShowRegValue(reg_id);
        }
        else  
         DisplayErrorMessage();
    }
    else
        DisplayErrorMessage();
}//end of ::CpuSetRegfromShell();

//added to support set cpu module 95.10.25
BOOL CCpuServer::GetCpuListFromFile()
{
 //get file path and create file full name
 CString tblFileName = "",fileBuf;
 int result=-1;
 tblFileName += szAppPath;
 tblFileName += "REGTBL.DAT";
 //open the file
 CStdioFile tblFile;
 if( !tblFile.Open( (const char *)tblFileName,
           CFile::modeRead | CFile::typeText ) )
  {
   //AfxMessageBox((const char *)(tblFileName+" not found!"));
   return FALSE;
   }
 //get cpu name
 do
  {
   if(NULL==tblFile.ReadString(fileBuf.GetBuffer(300),300))
    { fileBuf.ReleaseBuffer(); return FALSE; }
   fileBuf.ReleaseBuffer();
   result=fileBuf.Find("CPU_MODULE_LIST");
   } while(result==-1);

 for(UINT i=0; i<MAXCPUNUM; i++)
  {
   if(NULL==tblFile.ReadString(fileBuf.GetBuffer(300),300))
   { fileBuf.ReleaseBuffer(); return FALSE; }
   fileBuf.ReleaseBuffer();           
   result=fileBuf.Find("COMMON_REG");
   if(result!=-1) break;
   result=fileBuf.Find("EP");
   if(result==-1) break; 
   result+=2;  int tmp0=0;
   if(fileBuf.Find("SUPPORT")!=-1) 
   {
     char sz[16]="";
     while(fileBuf[result]!=' ' && fileBuf[result]!=',' && fileBuf[result]!=0)
     {
        sz[tmp0++]=fileBuf[result++];       
     } 
     sz[tmp0++]=0; 
     cpuNameList[sMaxCpuNum]=sz;
//   cpuNameList[sMaxCpuNum][tmp0++]=0;  
     cpuIDList[sMaxCpuNum] =(short) i;
     sMaxCpuNum++;
   }
 }         
 return TRUE;
}

BOOL CCpuServer::GetRegFromFile()
{
 //get file path and create file full name
 CString tblFileName = "",fileBuf;
 int result=-1;
 tblFileName += szAppPath;
 tblFileName += "REGTBL.DAT";
 //open the file
 CStdioFile tblFile;
 if( !tblFile.Open( (const char *)tblFileName,
           CFile::modeRead | CFile::typeText ) )
  {
   //AfxMessageBox((const char *)(tblFileName+" not found!"));
   return FALSE;
   }
 //get cpu name
 do
  {
   if(NULL==tblFile.ReadString(fileBuf.GetBuffer(300),300))
    { fileBuf.ReleaseBuffer(); return FALSE; }
   fileBuf.ReleaseBuffer();
   result=fileBuf.Find("CPU_MODULE_LIST");
   } while(result==-1);

 for(UINT i=0; i<CpuModule+1; i++)
  {
   if(NULL==tblFile.ReadString(fileBuf.GetBuffer(300),300))
    { fileBuf.ReleaseBuffer(); return FALSE; }
   fileBuf.ReleaseBuffer();
   }
                                    
 result=fileBuf.Find("EP");
 if(result==-1) return FALSE;
 result+=2;  int tmp0=0;
 while(fileBuf[result]!=' ' && fileBuf[result]!=',' && fileBuf[result]!=0)
  cpuModule.cpuName[tmp0++]=fileBuf[result++];
 cpuModule.cpuName[tmp0++]=0;
 //get common reg
 int tmpY=0,tmpX=0,tmpNo=0,tmpID=0; char *tmpPoint;
 do
  {
   if(NULL==tblFile.ReadString(fileBuf.GetBuffer(300),300))
    { fileBuf.ReleaseBuffer(); return FALSE; }
   fileBuf.ReleaseBuffer();
   result=fileBuf.Find("COMMON_REG");
   } while(result==-1);

 while(TRUE)
 {
 tmpPoint=fileBuf.GetBuffer(300);
 if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
 if(NULL!=strstr(tmpPoint,"COMMON_END")) break;

 while(tmpPoint!=NULL)
  {
   tmpPoint=strstr(tmpPoint,"REG_");
   if(tmpPoint==NULL) break;
   tmpPoint+=4;
   tmp0=0;
   while(tmpPoint[tmp0]!=' ' && tmpPoint[tmp0]!=',' && tmpPoint[tmp0]!=0)
    {
     cpuModule.RegNameID[tmpNo].Name[tmp0]=tmpPoint[tmp0];
     tmp0++;
     }
   if(tmp0>0)
   {
    cpuModule.RegNameID[tmpNo].Name[tmp0]=0;
    cpuModule.RegNameID[tmpNo].locY=tmpY;
    cpuModule.RegNameID[tmpNo].locX=tmpX++;
    cpuModule.RegNameID[tmpNo].ID=(unsigned char)tmpID;
    tmpNo++;
   }    
    tmpID++;
  }
  tmpX=0; tmpY++;
  fileBuf.ReleaseBuffer();
}//WHILE(TRUE)

 //get reg
 do
  {
   if(NULL==tblFile.ReadString(fileBuf.GetBuffer(300),300))
    { fileBuf.ReleaseBuffer(); return FALSE; }
   fileBuf.ReleaseBuffer();
   result=fileBuf.Find(cpuModule.cpuName);
   } while(result==-1);

 while(TRUE)
 {
 tmpPoint=fileBuf.GetBuffer(300);
 if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
 if(NULL!=strstr(tmpPoint,"REG_END")) break;

 while(tmpPoint!=NULL)
  {
   tmpPoint=strstr(tmpPoint,"REG_");
   if(tmpPoint==NULL) break;
   tmpPoint+=4;
   tmp0=0;
   while(tmpPoint[tmp0]!=' ' && tmpPoint[tmp0]!=',' && tmpPoint[tmp0]!=0)
    {
     cpuModule.RegNameID[tmpNo].Name[tmp0]=tmpPoint[tmp0];
     tmp0++;
     }
   if(tmp0>0)
   {
    cpuModule.RegNameID[tmpNo].Name[tmp0]=0;
    cpuModule.RegNameID[tmpNo].locY=tmpY;
    cpuModule.RegNameID[tmpNo].locX=tmpX++;
    cpuModule.RegNameID[tmpNo].ID=(unsigned char)tmpID;
    tmpNo++;
   }    
    tmpID++;
  }
 tmpX=0; tmpY++;
 fileBuf.ReleaseBuffer();
 }//WHILE(TRUE)

 cpuModule.nMaxReg=tmpNo;

 //GET CPU MEMORY INFORMATION
 //GET PDATA
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if((tmpPoint=strstr(tmpPoint,"PDATA"))==NULL) return FALSE;

   tmpPoint+=5;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(cpuMemoryRange.pMin))!=0)
    return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(cpuMemoryRange.pMax))!=0)
    return FALSE;
   fileBuf.ReleaseBuffer();
  }

//Get Banks
{
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"BANKS"))) return FALSE;

   tmpPoint+=5;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>1) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),(unsigned short*)&(m_cpuRFileRange.nBanks))!=0)
    return FALSE;
}


{
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"RDATA"))) return FALSE;

   tmpPoint+=5;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[32];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
//   if(iTmpDo>1) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
//   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(m_cpuRFileRange.nBanks))!=0)
//    return FALSE;
   char tmp[4][7]={"","","",""};
   char *token;    
   int i=0;
   token=strtok(&strTmpDo[0],";");
   while(token!=NULL)
   {
        strcpy(&tmp[i][0],token);  
        token=strtok(NULL,";");
        i++;
   }    
   unsigned char szv[4];
   int j=0,m;
   for(i=0;i<m_cpuRFileRange.nBanks;i++)
   {
        j=0;
        while(tmp[i][j]!='-'&&tmp[i][j]!='\0')
        {
            szv[j]=tmp[i][j];
            j++;
        }                                    
        szv[j++]=0;
        StrtoHex(szv,(unsigned short*)&(m_cpuRFileRange.RFileRange[i].nStartAddr));                                              
        m=0;
        while(tmp[i][j]!='-'&&tmp[i][j]!='\0')
        {
            szv[m++]=tmp[i][j];
            j++;
        }                                    
        szv[m]=0;
        StrtoHex(szv,(unsigned short*)&(m_cpuRFileRange.RFileRange[i].nEndAddr));                                                
   }                        
    
}

 //GET IDATA
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==(tmpPoint=tblFile.ReadString(tmpPoint,300))) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"STKST"))) return FALSE;

   tmpPoint+=5;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
//   if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),(unsigned short*)&(cpuModule.nStack))!=0)
    return FALSE;
  }
/*
 //GET RDATA
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"RDATA"))) return FALSE;

   tmpPoint+=5;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(cpuMemoryRange.rMin))!=0)
    return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(cpuMemoryRange.rMax))!=0)
    return FALSE;
   fileBuf.ReleaseBuffer();
  }

 //GET BDATA
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"BDATA"))) return FALSE;

   tmpPoint+=5;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(cpuMemoryRange.bMin))!=0)
    return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>5) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(cpuMemoryRange.bMax))!=0)
    return FALSE;
   fileBuf.ReleaseBuffer();
  }
*/
 // Get MCLR
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"MCLR"))) return FALSE;

   tmpPoint+=4;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>1) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(controlOption.controlMclr))!=0)
    return FALSE;

  }

 //GET Watchdog
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"WT"))) return FALSE;

   tmpPoint+=2;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>1) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(controlOption.controlWdg))!=0)
    return FALSE;

  }

 //GET Peripheral
 {
   tmpPoint=fileBuf.GetBuffer(300);
   if(NULL==tblFile.ReadString(tmpPoint,300)) return FALSE;
   if(NULL==(tmpPoint=strstr(tmpPoint,"PERI"))) return FALSE;

   tmpPoint+=4;
   if(tmpPoint==NULL) return FALSE;

   while ((*tmpPoint)==' ' || (*tmpPoint)==',') tmpPoint++;
   char strTmpDo[8];  char iTmpDo=0;
   while (tmpPoint[iTmpDo]!=' ' && tmpPoint[iTmpDo]!=','
          && tmpPoint[iTmpDo]!=0 && tmpPoint[iTmpDo]!='\n')
    {
     strTmpDo[iTmpDo]=tmpPoint[iTmpDo];
     iTmpDo++;
     if(iTmpDo>1) return FALSE;
     }
   tmpPoint=&(tmpPoint[iTmpDo]); strTmpDo[iTmpDo]=0;
   if(StrtoHex((unsigned char *)(&(strTmpDo[0])),&(controlOption.controlPeri))!=0)
    return FALSE;
  }

 return TRUE;
} 


 
CString *PreCpuInitialize(int &iRoger)              
{ 
 return CpuSrv.PreCpuInitialize(iRoger);
}   
 
 
//added to support set cpu module 95.10.25
CString* CCpuServer::PreCpuInitialize(int &iRoger)             
{               
 int tmp0;
 tmp0=0;
 if (CpuSrv.GetCpuListFromFile()==FALSE) return 0;//initial error,quit
 UINT wCpuNum;
 UINT wCpuType[40];
 m_nErrorID=AbiGetTargetSupport(&wCpuNum,wCpuType);
 if(ICE_OK!=m_nErrorID) return 0;
 if(wCpuNum == 0) return 0;
 
 for(UINT tmp=0;tmp<wCpuNum;tmp++)
  { 
   for(UINT tmp2=0;tmp2<CpuSrv.sMaxCpuNum;tmp2++)
   { 
     if(cpuIDList[tmp2] == wCpuType[tmp])  
     {
       cpuIDValid[tmp0] = cpuIDList[tmp2];
       cpuNameValid[tmp0]=cpuNameList[tmp2];
       tmp0++;
   }
 }
}
 cpuNameValid[0]+=" (Default)";
 sMaxCpuValid = iRoger = tmp0;
 return (CString*)CpuSrv.cpuNameValid;
 }
//return FALSE: initial error,quit
//return TURE: OK             

BOOL CCpuServer::Initialize(int iRoger)
{
UINT CpuId;                
int i;
    
    if(iRoger>=sMaxCpuNum) return FALSE;
    
    if(iRoger==-1)  
     {
      m_nErrorID = AbiGetCpuId(&CpuId);
      if(ICE_OK!=m_nErrorID) return FALSE;
      }
     else
      CpuId=cpuIDValid[iRoger];
    
    UINT tmpRoger;   
    m_nErrorID = AbiSetCpuId((UINT) CpuId, &tmpRoger);
    CpuId = 1; tmpRoger = 1;
    if(m_nErrorID!=ICE_OK || CpuId!=tmpRoger) 
     { 
      m_nErrorID = AbiGetCpuId(&CpuId);
      if(ICE_OK!=m_nErrorID) return FALSE;
      ErrDisplayError(ER_PRE_CPU_SETTING);
      }
    
    if(TRUE)
    {   
        #ifdef _320
        CpuId = 50;
        #endif
        switch (CpuId)//suport dad
        {
         case  8:  //EP80C152JA
         case  9:  //EP83C152JA
         case 12:  //EP80C152JC
         case 13:  //EP83C152JC
                   gEPModule=8; break;

         case 10:  //EP80C152JB
         case 11:  //EP83C152JB
         case 14:  //EP80C152JD
         case 15:  //EP83C152JD
                   gEPModule=10; break;
         case 16:  //80c51fa,fb,fc
         case 17:  //83c51fa,fb,fc
                   gEPModule = 16;  //added by john 96.2
                   break;       
         default:  gEPModule=(unsigned char)CpuId;  break;
         }

        CpuModule = CpuId;
        if(FALSE==GetRegFromFile()) //added by john 95.8
         //AfxMessageBox("Register Table Loading Error!");
         return FALSE;
        CpuName = cpuModule.cpuName;
        nMaxReg = cpuModule.nMaxReg;
        //AbiSetRegNumber((UINT) nMaxReg);

        for(i=0;i<MAX_REGISTERS;i++)
        {
            RegName[i]= cpuModule.RegNameID[i].Name;
        }
    return TRUE;
    }
    else  { /*DisplayErrorMessageBox();*/ return FALSE; }
}

void GetCpuName(CString& strName)
{
    strName = CpuSrv.CpuName;
}


/*void CCpuServer::ShowModule()
{
UINT CpuId;
int i;
char DisplayStr[30];
    m_nErrorID = AbiGetCpuId(&CpuId);
    if(ICE_OK==m_nErrorID)
    {
        if(CpuId!=CpuModule)
        {
            CpuModule = CpuId;
            CpuName = cpuModule[CpuId].cpuName;
            nMaxReg = cpuModule[CpuId].nMaxReg;

            for(i=0;i<nMaxReg;i++)
            {
                RegName[i]= cpuModule[CpuId].RegNameID[i].Name;
            }
            ShowAllRegToWnd();
        }
        wsprintf(DisplayStr,"The Cpu module is %s",CpuName) ;
        ShowLine(DisplayStr);
    }
} */

/*void CCpuServer::SetModule(UINT CpuId)
{
char DisplayStr[30];
int i;

    if(bCpuSetFlag)
    {
        ShowLine("The cpu module has already been set!");
        return;
    }

    if(CpuId!=CpuModule)
    {
        if(ICE_OK==AbiSetCpuId(CpuId,&CpuId))
        {
            CpuModule = CpuId;
            CpuName = cpuModule[CpuId].cpuName;
            nMaxReg = cpuModule[CpuId].nMaxReg;

            for(i=0;i<nMaxReg;i++)
            {
                RegName[i]= cpuModule[CpuId].RegNameID[i].Name;
            }
            ShowAllRegToWnd();
            bCpuSetFlag = 1;
        }
        else return;       //time out
    }
    wsprintf(DisplayStr,"The Cpu module is %s",CpuName);
    ShowLine(DisplayStr);
} */

BOOL CCpuServer::ResetbyWnd(WORD addr)
{

ADDR address;
    address.addrType = 1;
    address.addr = addr;
    m_nErrorID = AbiReset(address);

    if(ICE_OK == m_nErrorID)
    {
        ShowAllRegToWnd();
        //send message to all windows

        // Added by John.
        GetXviewAppJohn()->m_nCpuStatus = STATUS_HALT;

        // Add elapse timer.
        ((CMainFrame*)((CXviewApp*)AfxGetApp())->m_pMainWnd)->ShowElapseTimer();

        return(TRUE);
    }
    else
    {
        DisplayErrorMessageBox();
        return(FALSE);
    }
}


void CCpuServer::ResetbyShell(WORD addr)
{
ADDR address;
    address.addrType = 1;
    address.addr = addr;
    m_nErrorID = AbiReset(address);

    if(ICE_OK == m_nErrorID)
    {
        ShowAllRegToWnd();
        //send message to all windows

        // Added by John.
        GetXviewAppJohn()->m_nCpuStatus = STATUS_HALT;

        // Add elapse timer.
        ((CMainFrame*)((CXviewApp*)AfxGetApp())->m_pMainWnd)->ShowElapseTimer();
    }
    else
        DisplayErrorMessage();
}

void CCpuServer::DisplayErrorMessage(void) const
{
    CString str;
    switch (m_nErrorID){ 
    
      case 1:  ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));
               str.ReleaseBuffer();                  
           break;//target cannot step
      case 2:ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
           break;             //memory write failure
      case 3: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
           break;          //map status not included
      case 4: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
           break;           //map address boundary error
      case 5: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;
      case 6: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;
      case 7 :ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;
      case 8: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;

      case 16: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;
      case 17:ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;
      case 18: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
           break;
      case 19: ErrGetErrorText(ER_ICE_OK+m_nErrorID,str);
               ShowLine( str.GetBuffer(str.GetLength()));                  
               str.ReleaseBuffer();
            break;      
      default: ErrGetErrorText(ER_ICE_DEFAULT_ERROR,str);
               ShowLine( str.GetBuffer(str.GetLength()));     
               str.ReleaseBuffer();
            break;   
   }   
}   // End of CCpuServer::DisplayErrorMessage().


void CCpuServer::DisplayErrorMessageBox(void) const
{
   //FOR  Display the ABI error message using
    switch (m_nErrorID){
      case 1:  ErrDisplayError(ER_ICE_OK+m_nErrorID);                  
           break;//target cannot step
      case 2:ErrDisplayError(ER_ICE_OK+m_nErrorID); 
           break;             //memory write failure
      case 3: ErrDisplayError(ER_ICE_OK+m_nErrorID); 
           break;          //map status not included
      case 4: ErrDisplayError(ER_ICE_OK+m_nErrorID); 
           break;           //map address boundary error
      case 5: ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;
      case 6: ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;
      case 7 :ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;
      case 8: ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;
      case 16:ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;
      case 17:ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;
      case 18:ErrDisplayError(ER_ICE_OK+m_nErrorID); 
           break;    
      case 19: ErrDisplayError(ER_ICE_OK+m_nErrorID); 
            break;     
      default: ErrDisplayError(ER_ICE_DEFAULT_ERROR);
   }   
}   // End of CCpuServer::DisplayErrorMessageBox().

//editted by John.Chow 95.6 to add a private routine to show all reg in shell
void CCpuServer::ShowAllRegByArray()//only used in ShowAllRegToShell()
{
 int i,k1,k2,k3;
 char DisplayStr[20];
 char DisplayWholeStr[100];
 /*char (*tmpBuffer)[MAXLINES][MAXALINE];
 tmpBuffer=new char[MAXCHARS][MAXLINES][MAXALINE];*/
 char *tmpBuffer[MAXLINES][MAXALINE];
 for(k1=0;k1<MAXLINES;k1++)
  for(k2=0;k2<MAXALINE;k2++)
   tmpBuffer[k1][k2]=new char[MAXCHARS];

        for(k1=0;k1<MAXLINES;k1++)
         for(k2=0;k2<MAXALINE;k2++)
          for(k3=0;k3<MAXCHARS;k3++)
          tmpBuffer[k1][k2][k3]=0;

        i=0;
        int j=0;
        while ( j<nMaxReg )
        {
          if(IsIDValid(i))
          { 
           if(i<9)
              wsprintf(DisplayStr,"%s=%04X",RegName[j],RegValue[i]);
           else
              wsprintf(DisplayStr,"%s=%02X",RegName[j],RegValue[i]);

           if(cpuModule.RegNameID[j].locY>=MAXLINES) break;
           strcat(tmpBuffer[cpuModule.RegNameID[j].locY]
                           [cpuModule.RegNameID[j].locX],
                  DisplayStr);
           j++;       
          }          
          i++;
        }//while

           for(k1=0;k1<MAXLINES;k1++)
            {
             DisplayWholeStr[0]=0;
             for(k2=0;k2<MAXALINE;k2++)
              {
               if(tmpBuffer[k1][k2][0]!=0)
                {
                 strcat(DisplayWholeStr,tmpBuffer[k1][k2]);
                 strcat(DisplayWholeStr," ");
                 }
               }
             if(DisplayWholeStr[0]!=0) ShowLine(DisplayWholeStr);
             }
                                        
 for(k1=0;k1<MAXLINES;k1++)
  for(k2=0;k2<MAXALINE;k2++)
   delete []tmpBuffer[k1][k2];
 //delete []tmpBuffer;     
 }

//these two routines are added to give cpu information
int GetMemoryRange(CPUMEMORYRANGE *stRange)
{
 memcpy(stRange,&(CpuSrv.cpuMemoryRange),sizeof(CPUMEMORYRANGE));
 return 0;
 }

int GetControlOption(CString &strMclr,CString &strWdg,CString &strPeri)
{
 if(CpuSrv.controlOption.controlMclr==1) strMclr="MCLR"; else strMclr="";
 if(CpuSrv.controlOption.controlWdg==1) strWdg="WATCHDOG"; else strWdg="";
 if(CpuSrv.controlOption.controlPeri==1) strPeri="PERIPHERAL"; else strPeri="";
 return 0;
 }

//added to support the set cpu module 95.10.25
//initial the cpuserver
CCpuServer::CCpuServer()
{                      
  bCpuSetFlag=0;
  CpuModule=1;
  CpuName="8032";            
  sMaxCpuNum = 0;   
  
  typedef char * PCHAR;
  
  cpuNameList = new CString[MAXCPUNUM];
//  for(int i = 0; i < MAXCPUNUM; i ++) {
//  cpuNameList[i] = new char [MAXCPUNAMELENGTH];  }
    
  cpuNameValid = new CString[MAXCPUNUM];
//  for(i = 0; i < MAXCPUNUM; i ++) {
//  cpuNameValid[i] = new char [MAXCPUNAMELENGTH];  }
 }

CCpuServer::~CCpuServer()
{
//  for(int i = 0; i < MAXCPUNUM; i ++) delete [] cpuNameList[i];
  delete []cpuNameList;        
  
//  for(i = 0; i < MAXCPUNUM; i ++) delete [] cpuNameValid[i];
  delete []cpuNameValid;        
}
///////////////////////////////(EOF)////////////////////////////////


int StrtoHex(unsigned char *InputStr,unsigned short *Output)
{
 int i,j;
 unsigned long kk,k;                
 unsigned char Input[256];
 unsigned char *P;
 //copy the inputstr                                
 for(i=0;InputStr[i]!=0;i++) Input[i]=InputStr[i];
 Input[i]=0;
                                 
 for(P=Input;*P=='0' && P[1]=='0';P++);
 for(;*P!=0;P++)
     *P=(*P>='a' && *P<='z')?(unsigned char)(*P-'a'+'A'):*P;
 
 i=strlen((char *)Input);  kk=0;k=1;  *Output=0;
 if(i==0) return -101;
 if(Input[i-1]=='H') i--;
 if(i==0 || i>5) return -101;
 for(j=i;j>0;j--)
  {
   if(!(Input[j-1]>='0' && Input[j-1]<='9') && !(Input[j-1]>='A' && Input[j-1]<='F')) return -101;
   if(Input[j-1]>='A' && Input[j-1]<='F') Input[j-1]=(unsigned char)(Input[j-1]-'A'+'9'+1);
   kk+=k*(Input[j-1]-'0');
   k*=16;
   }

 if(kk>0x0ffff) return -102;
 *Output=(unsigned short)(kk);
 return 0;//ok
}

