/***************************************************************************
**
**    $Header: 
**
**    $Log:                            
****************************************************************************/

/***************************************************************************
**
** File name : TRCSERVE.CPP 
** Author: BRIGHT CHEN, Chris Fang, Richard
** Description:
**
** Copyright (C) 1997 Microtek International, Inc.
** All Rights Reserved
**
****************************************************************************/

#include "stdafx.h"

#include <ctype.h>

#include "trcserve.h"                       
#include "hosterrs.h"
#include "ep196.h"

#define INRANGE(a, b, c) 	((a)>=(b)&&(a)<=(c))
#define ARRAYCOUNT(p) 	sizeof(p)/sizeof(*p)

#define MAX_LIST_LINE	100
#define ER_GOFLY_ERR_MSG	0x4555
static const char* g_range = "Range";
static const char* g_on = "On";
static const char* g_off = "Off";
static const char* g_event = "Ev";
static const char* g_level = "Lv";
static const char* g_trace = "Trace";
static const char* g_timer = "Timer";    
static const char* g_address = "Address";
static const char* g_data = "Datum";
static const char* g_status = "Status";
static const char* g_count = "Count";
static const char* g_clear = "Clear";                
static const char* g_low = "Low";
static const char* g_high = "High";         
static const char* g_trigger = "Trigger";  
static const char* g_delay = "Delay";
static const char* g_forward = "Forward";
static const char* g_backward = "Backward";
static const char* g_center = "Center";
static const char* g_or	= "Or";
static const char* g_and = "And";
static const char* g_then = "Then";                  
static const char* g_run = "Run";       
static const char* g_number = "Number";
static const char* g_control = "Control";       
static const char* g_reset = "Reset";
static const char* g_nmi = "Nmi";
static const char* g_enable = "Enable";
static const char* g_disable = "Disable";
static const char* g_is = "Is";
static const char* g_is_clear = "is clear";
static const char* g_set_success = "is set successfully.";
static const char* g_clear_success = "is clear successfully.";  
static const char* g_trace_empty = "Trace buffer is empty.";
static const char* g_trace_last_frame = "The last frame number is %04lX.";

static const char* statusTbl[] = 
	{ "S", "W", "R", "AK", "  "};

static struct LVCond
{
	DWORD	dwCond;
	char*	szCond;
}g_levelCond[] =
{
  {  0xaaaaaaaa , "ev1 "},
  {  0xcccccccc , "ev2 "},
  {  0xf0f0f0f0 , "ev3 "},     
  {  0x88888888 , "ev1 and ev2 "},
  {  0xa0a0a0a0 , "ev1 and ev3 "},
  {  0xc0c0c0c0 , "ev2 and ev3 "},
  {  0xeeeeeeee , "ev1 or ev2 "},
  {  0xfafafafa , "ev1 or ev3 "},
  {  0xfcfcfcfc , "ev2 or ev3 "},
  {  0x80808080 , "ev1 and ev2 and ev3 "},
  {  0xfefefefe , "ev1 or ev2 or ev3 "},
  {  0xf8f8f8f8 , "ev1 and ev2 or ev3 "},
  {  0xecececec , "ev1 and ev3 or ev2 "},
  {  0xeaeaeaea , "ev2 and ev3 or ev1 "},
  {  0xe0e0e0e0 , "ev1 or ev2 and ev3 "},
  {  0xc8c8c8c8 , "ev1 or ev3 and ev2 "},            
  {  0xa8a8a8a8 , "ev2 or ev3 and ev1 "},
};   

extern void ShowLine(char*);
extern int  TestKey(WORD);

	
BOOL IsEpRunning()
{
	DWORD dwValue;
	
	emuGetCpuStatus(&dwValue);
	
	if (dwValue & 0x10)
		return TRUE;
	else return FALSE;
}

/****************************************************************************
**	class CTraceBase
**  base class for all trace related class
**	Coding from: Apr. 21
**	Finish date:
****************************************************************************/
void CTraceBase::Serialize(CArchive& ar)
{   
	WORD wClear;
    if(ar.IsStoring())
        ar << (WORD)m_nClearFlag;
    else{
        ar >> wClear;
        m_nClearFlag = (int)wClear; 
    }
}

BOOL CTraceBase::IsKeyword(const char* ob, const char* key)
{
	return (!_stricmp(key, ob));
}

BOOL CTraceBase::IsContainKeyword(const char* ob, const char* key)
{
	return (!_strnicmp(key, ob, strlen(key)));
}

BOOL CTraceBase::IsPAddr(char* p, DWORD& dwAddr)
{
	DWORD dwBank = 0;           

	while((isspace(*p) || *p=='(' || *p=='<' ||
		*p==')' || *p=='>') && (*p != NULL))  p++;

	if (*p == NULL) return FALSE;
		
	if((p[0]=='P'||p[0]=='p')&&p[2]==':')
	{
		dwBank = ((DWORD)(p[1]-'0'))<<16;
		p+=3;                   
	}   
//	else return FALSE;  // for Address range, the second address may not have "PX:"
		
	dwAddr = strtoul(p, NULL, 16) + dwBank;
	
	return TRUE;
}

BOOL CTraceBase::IsEventData(char* p, WORD& wData)
{                       
	if(!isNum(p))
		return FALSE;

	wData = (WORD)strtoul(p, NULL, 16);
	
	return TRUE;
}

BOOL CTraceBase::IsCount(char* p, WORD& wData)
{
	return IsEventData(p, wData);
}

BOOL CTraceBase::IsListFrame(char* p, DWORD& dwData)
{
	if(!isNum(p))
		return FALSE;

	dwData = strtoul(p, NULL, 16);
	
	return TRUE;
}

BOOL CTraceBase::isNum(char * p)
{          
	ASSERT(p);
	
	if (!(*p)) return FALSE;
	
	BOOL bFlag = FALSE;
    
    while(*p){
		if(isxdigit(*p))
			bFlag = TRUE;
		else{
			if( (*p==')') || (*p=='>') ) return bFlag;	
			else return FALSE;
		}
		p++;
	}
	
	return bFlag;
}

BOOL CTraceBase::IsWildCard(char * p)
{
	if(strchr(p, 'X')||strchr(p,'x'))
		return TRUE;
	else
		return FALSE;	
}

//this function check if the str is stuatus s f ........
//return value refers the status
//return <0 refer to not found
int CTraceBase::IsStatus(char *str)
{
   ASSERT( str );
   CString strx= strupr(str);
   
   if ( strx == "S") return STATUS_S;
//   if ( strx == "F") return STATUS_F;
   if ( strx == "R") return STATUS_R;
   if ( strx == "W") return STATUS_W;
   if ( strx == "AK") return STATUS_AK;
   return -1;
}

int CTraceBase::StrChrNum(const char *szStr, char ch)
{
	ASSERT (szStr != NULL);
	
	int nNum = 0;
	
	while(*szStr){
		if (*szStr++ == ch) nNum++;
	}
	
	return nNum;
}

int CTraceBase::StrChrNumNoCase(const char *szStr, char ch)
{
	ASSERT (szStr != NULL);
	int nNum = 0;
	
	ch = (char)toupper(ch);
	
	while(*szStr){
		if (toupper(*szStr) == ch) nNum++;
		szStr++;
	}
	
	return nNum;
}                       

int CTraceBase::GetAddrBank(DWORD dwAddr)
{// 18 bit address
	return (int)((dwAddr >> 16) & 0x3);
}

void CTraceBase::StrFromValue(char* szStr, DWORD dwValue, int nLen)
{
	ASSERT(szStr != NULL);
	
	for(int i=nLen-1; i>=0; i--)
	{	                 
		szStr[i] = (dwValue & 1)? '1' : '0';
		
		dwValue >>= 1;
	}                                       
	szStr[nLen] = '\0';
}
	
void CTraceBase::StrFromValueMask(char* szStr, DWORD dwValue, 
	DWORD dwMask, int nLen, int nAddrType)
{
	ASSERT (szStr != NULL);
    
    if (nAddrType==ADDR_TYPE){// Address
    	if (GetAddrBank(dwMask) == 0) // no bank mask
    	{                                               
    		wsprintf(szStr, "P%1d:", GetAddrBank(dwValue));
    		szStr += strlen(szStr);
    	}
    }

   	*(szStr++) = '(';

	BOOL bBinary = FALSE;
	if (nLen%4==0) // see if it can be presented in hexadecimal 
	{
		for(int j=0; j<nLen/4; j++)
		{
			if ( ((dwMask>>j*4) & 0xf)!=0xf &&
				 ((dwMask>>j*4) & 0xf)!=0 )
			{
				bBinary = TRUE;
				break;
			}
		}
	}
	
	
	if (bBinary)
	{					
		for (int i=nLen-1; i>=0; i--)
		{
			if (dwMask & 1)
				szStr[i] = 'X';
			else szStr[i] = (dwValue & 1)? '1' : '0';
		
			dwMask >>= 1;
			dwValue >>= 1;
		}	                      
    
	    wsprintf(szStr+nLen, "B) ");
	}
	else
	{
		for(int i=nLen/4-1; i>=0; i--)
		{
			if (dwMask & 0xf)
				szStr[i] = 'X';
			else szStr[i] = ((dwValue & 0xf)<=9)? 
				'0'+(dwValue & 0xf) : 'A'+((dwValue & 0xf)-10);
		
			dwMask >>= 4;
			dwValue >>= 4;
		}	             
		
		wsprintf(szStr+nLen/4, ") ");
	}   
}


// szStr must have been syntax checked, I do not check whether szStr is valid
void CTraceBase::ValueMaskFromStr(const char* szStr, DWORD& dwValue, 
		DWORD& dwMask, int nBase, int nAddrType)
{
	ASSERT (szStr != NULL);
	ASSERT (nBase==2 || nBase==16);
	
	dwValue = 0;
	dwMask = 0;
                   
	// filter redundant character	
	char *pBegCur = strchr(szStr, '(') + 1;  // exist ( in mask address 
	char *pEndCur;
	
	char *szTemp = new char[strlen(pBegCur) + 1];
	
	if (!szTemp) return;                         

	strcpy(szTemp, pBegCur);
	strupr(szTemp); // toupper

	if (nBase==2)
		pEndCur = strchr(szTemp, 'B');
	else pEndCur = strchr(szTemp, ')');		
	
	*pEndCur = '\0';
		
    // now pure wild card address
	DWORD dwEachMask = 1;
	if (nBase==16) dwEachMask = 0xF;
	
	char *pHead = szTemp;
	while(*szTemp){         

		dwMask *= nBase;

		if (*szTemp == 'X'){
			dwMask += dwEachMask;
			*szTemp = '0';				
		}                 
		szTemp ++;
	}                    
	
	dwValue = strtoul(pHead, NULL, nBase);
	
	if (nAddrType == ADDR_TYPE){  // address have bank information
		if (toupper(*szStr)=='P'){
			dwValue |= ((DWORD)(szStr[1]-'0'))<<16; // add bank information
		}
		else{// mask bank
			dwMask |= 3L << 16;
		}
	}
	
	delete [] pHead;
}

CTraceBase::CTraceBase()
{
}

CTraceBase::~CTraceBase()
{
}

BOOL CTraceBase::Init()
{                    
	m_nArgMax = 0;
	return TRUE;
}            

BOOL CTraceBase::RestoreSet()
{
	return TRUE;
}

void CTraceBase::PreStoreArg(int nArgc, char** pszArgv)
{
    ASSERT( nArgc > 0 );
    for ( int i = 0; i <nArgc; i++ ) ASSERT( pszArgv[i] );
    
    m_nArgMax = nArgc;
    
    for (i=0; i< nArgc; i++)
    	m_pArgPoint[i] = pszArgv[i];
}

void CTraceBase::ShellCmd(int nArgc, char** pszArgv)
{ 
	PreStoreArg(nArgc, pszArgv);
	ResetTmpData();
}

void CTraceBase::ResetTmpData()
{
}

void CTraceBase::ResetContents(void* /*pData*/)
{
}

int CTraceBase::SetFW()
{
	return ICE_OK;
}

void CTraceBase::SimplifySet()
{
}

void CTraceBase::ShowToShell()
{    
	ShowLine(m_strDisplay.GetBuffer(m_strDisplay.GetLength()));
	m_strDisplay.ReleaseBuffer();
}

void CTraceBase::SetByShell()
{
}

void CTraceBase::Clear()
{           
}

BOOL CTraceBase::IsBinary(const char* pszArgv, int nAddrType)
{
	if ( 'B' == toupper(*(pszArgv+strlen(pszArgv)-2)) )
	{ // perhaps exist 'B' in hexdecimal string
		if (nAddrType==DATA_TYPE) // data type, '(' + 8 bit wild card + 'B' + ')'
			return strlen(pszArgv)>10 ? TRUE : FALSE;
		else // address type, '(' + 16 bit wild card + 'B' + ')'                  
			return strlen(pszArgv)>18 ? TRUE : FALSE;
	}
	
	return FALSE;
}
		
CTraceBase::CardType 
CTraceBase::WildCard(const char* pszArgv, DWORD& dwValue, DWORD& dwMask,
		int nAddrType)
{  
	ASSERT (pszArgv != NULL);
	
	int nLen = strlen(pszArgv);
	
	char chWild = 'X';       
	
	int nWildNum = StrChrNumNoCase(pszArgv, chWild);
	
    // Binary or Hexadecimal wildcard code.
    if (IsBinary(pszArgv, nAddrType)) 
    { // Binary wildcard code
    	ValueMaskFromStr(pszArgv, dwValue, dwMask, 2, nAddrType);
    }
    else {
    	ValueMaskFromStr(pszArgv,dwValue, dwMask, 16, nAddrType);
    }
    
    if (nLen==nWildNum+2) 	return ALL_CARD;
    else if (nWildNum == 0) return SINGLE_CARD;
	else return MASK_CARD;
}

void CTraceBase::DisplayErrorMessage(unsigned long nErrorID, int nFlag)
{              
    char	 pszAbiError[150];

	ErrGetErrorText(nErrorID, pszAbiError);                           
	
	if (nFlag==SHOWINSHELL)
    	ShowLine(pszAbiError);
	else AfxMessageBox(pszAbiError);    	
}	                              
	

/****************************************************************************
**	class CBusEvent
**  class for event, such as event 1 and event  
**	Coding from: Apr. 21
**	Finish date:
****************************************************************************/
CBusEvent::CBusEvent()
{   
}

CBusEvent::CBusEvent(WORD wEventID)
{   
	m_wID = wEventID;
}

	
CBusEvent::~CBusEvent()
{           
}

void CBusEvent::Serialize(CArchive& ar)
{
    CTraceBase::Serialize(ar);
    
    if(ar.IsStoring()){
        ar << m_wID;
        ar.Write(&m_busEv, sizeof(BUS_EVENT));
    }
    else{
        ar >> m_wID;
        ar.Read(&m_busEv, sizeof(BUS_EVENT));
    }
}

void CBusEvent::WildCardAddr(char *pInput)
{ 
	ASSERT( pInput );

	DWORD dwValue, dwMask;
		
	WildCard(pInput, dwValue, dwMask, ADDR_TYPE);
	
	SetAddrType(ADDR_WILD_CARD);
	
	m_tmpBusEv.addrValue[0] = dwValue;
	m_tmpBusEv.addrValue[1] = dwMask;
}

void CBusEvent::WildCardData(char *pInput)
{
	ASSERT( pInput );

	DWORD dwValue, dwMask;
		
	WildCard(pInput, dwValue, dwMask, DATA_TYPE);
	
	SetDataType(DATA_WILD_CARD);
	
	m_tmpBusEv.dataValue1 = (WORD)dwValue;
	m_tmpBusEv.dataValue2 = (WORD)dwMask;
}

// because there are some differences in event structure in each project 
// I try to reduce their effects.
void CBusEvent::SetAddrType(int nType)
{               
	m_tmpBusEv.addrType = (BYTE)nType;
}

int CBusEvent::GetAddrType()
{
	return m_busEv.addrType;
}

void CBusEvent::SetDataWidth(int nByteNum)
{
	if (nByteNum==1){ // 8 bits
		m_tmpBusEv.dataType &= 0x7f;
	}
	else { // 16 bits
		m_tmpBusEv.dataType |= 0x80;
	}
}

int CBusEvent::GetDataWidth()
{
	return (m_busEv.dataType & 0x80)? 2 : 1;
}
                            
void CBusEvent::SetDataType(int nType)
{
	m_tmpBusEv.dataType &= 0x80;
	m_tmpBusEv.dataType |= nType;
}

int CBusEvent::GetDataType()
{
	return m_busEv.dataType & 0x7f;
}
                            
void CBusEvent::SetAddr(int& nIndexHere)
{ 
	ASSERT(nIndexHere < m_nArgMax);

	DWORD dwAddrVal;
	
	// first search if it is a range address
	if (IsKeyword(g_range, m_pArgPoint[nIndexHere]))
	{
		SetAddrType(ADDR_RANGE);
		
		nIndexHere++;
	    ASSERT(nIndexHere < m_nArgMax);

	    if (IsPAddr(m_pArgPoint[nIndexHere], dwAddrVal))
   			m_tmpBusEv.addrValue[0] = dwAddrVal;

	    nIndexHere++;
    	ASSERT(nIndexHere < m_nArgMax);

	    if (IsPAddr(m_pArgPoint[nIndexHere], dwAddrVal))
	    {
   			m_tmpBusEv.addrValue[1] = dwAddrVal;
   		    m_tmpBusEv.addrValue[1] |= ((DWORD)GetAddrBank(m_tmpBusEv.addrValue[0]))
   		    							<< 16;
   		}

    	
    	nIndexHere++;
    	m_tmpBusEv.addrCount = 2;
    }        
	else if(IsWildCard(m_pArgPoint[nIndexHere]))
    { //for wild card address  
    	WildCardAddr(m_pArgPoint[nIndexHere]);       
    	nIndexHere++;
    }
  	else if (IsPAddr(m_pArgPoint[nIndexHere], dwAddrVal)) 
   {  //for maximum ten addresses
	    SetAddrType(ADDR_GROUP); 
	    
	    BYTE nNum = 0;
        
        char* pCur = m_pArgPoint[nIndexHere];
        
		while(*pCur == ' ' || *pCur=='<')
   			pCur++; // bypass blank
        
        while(*pCur && IsPAddr(pCur, dwAddrVal) && nNum<10)
        {

       		m_tmpBusEv.addrValue[nNum++] = dwAddrVal;
       		pCur = strchr(pCur, ' ');
       		
       		if (pCur != NULL)              
       			do{
        			pCur++; // bypass blank
        		}while(*pCur == ' ' || *pCur == '>');
        	else break;
        }
        	
	    m_tmpBusEv.addrCount = nNum;
	    nIndexHere++;
    }//if
}//function

void CBusEvent::GetAddrStr(char* szBuf)
{
	int nType = GetAddrType();
	
	if (nType == ADDR_NOT_SET)
	{
		*szBuf = '\0';
		return;
	}

	wsprintf(szBuf, "Address ");
	szBuf += strlen(szBuf);
		
	switch(nType)
	{
		case ADDR_RANGE:      
		    wsprintf(szBuf, "%s P%1d:%04lX P%1d:%04lX ",
		    	g_range,
		    	GetAddrBank(m_busEv.addrValue[0]),
		     	m_busEv.addrValue[0] & 0xffff,
		     	GetAddrBank(m_busEv.addrValue[1]),
		     	m_busEv.addrValue[1] & 0xffff);
		    break;         
		case ADDR_EXCLUDE_RANGE:
		    wsprintf(szBuf, "~%s P%1d:%04lX P%1d:%04lX ",
		    	g_range,
		    	GetAddrBank(m_busEv.addrValue[0]),
		     	m_busEv.addrValue[0] & 0xffff,
		     	GetAddrBank(m_busEv.addrValue[1]),
		     	m_busEv.addrValue[1] & 0xffff);
		    break;         
		case ADDR_WILD_CARD:
			StrFromValueMask(szBuf, m_busEv.addrValue[0],
						m_busEv.addrValue[1], 16, ADDR_TYPE);
			break;
		case ADDR_GROUP:       
			strcpy(szBuf, "<");
			szBuf += strlen(szBuf);
			
			for (int i=0; i<m_busEv.addrCount; i++)
			{
				wsprintf(szBuf, "P%1d:%04lX ", 
					GetAddrBank(m_busEv.addrValue[i]),
					m_busEv.addrValue[i] & 0xffff);
				szBuf += strlen(szBuf);
			}                                         
			strcpy(szBuf-1, "> ");
	}
}

void CBusEvent::SetData(int &nIndexHere)
{       
	ASSERT(nIndexHere < m_nArgMax);

	if (IsKeyword("WORD", m_pArgPoint[nIndexHere]))
		SetDataWidth(2);
	else 
		SetDataWidth(1);
	
	nIndexHere++;
    ASSERT(nIndexHere < m_nArgMax);
		
	WORD wDataVal;
	
	// first search if it is a range data
	if (IsKeyword(g_range, m_pArgPoint[nIndexHere]))
	{
		SetDataType(DATA_RANGE);
		
		nIndexHere++;
	    ASSERT(nIndexHere < m_nArgMax);

	    if (IsEventData(m_pArgPoint[nIndexHere], wDataVal))
   			m_tmpBusEv.dataValue1 = wDataVal;

	    nIndexHere++;
    	ASSERT(nIndexHere < m_nArgMax);

	    if (IsEventData(m_pArgPoint[nIndexHere], wDataVal))
   			m_tmpBusEv.dataValue2 = wDataVal;
    	
    	nIndexHere++;
    }        
	else if(IsWildCard(m_pArgPoint[nIndexHere]))
    { //for wild card data  
    	WildCardData(m_pArgPoint[nIndexHere]);       
    	nIndexHere++;
    }
    
    else if ( IsEventData(m_pArgPoint[nIndexHere], wDataVal) ) 
	{   //for one addresses
                                                        
		SetDataType(DATA_SINGLE);
	    m_tmpBusEv.dataValue1 = wDataVal;
    	nIndexHere++;
    }//if
}

void CBusEvent::GetDataStr(char* szBuf)
{
	int nType = GetDataType();
	
	if (nType == DATA_NOT_SET)
	{
		*szBuf = '\0';
		return;
	}

	wsprintf(szBuf, "Datum ");
	szBuf += strlen(szBuf);

	int nWidth = GetDataWidth();	
	
	switch(nWidth){
		case 1:
			wsprintf(szBuf, "Byte ");
			break;
		case 2:
			wsprintf(szBuf, "Word ");
			break;
	}
	szBuf += strlen(szBuf);
	
	switch(nType)
	{
		case DATA_RANGE:       
			if (nWidth==1)
		    	wsprintf(szBuf, "%s 0X%02X 0X%02X ",
		    		g_range,
		     		m_busEv.dataValue1,
		     		m_busEv.dataValue2);
			else		     		
		    	wsprintf(szBuf, "%s 0X%04X 0X%04X ",
		    		g_range,
		     		m_busEv.dataValue1,
		     		m_busEv.dataValue2);
		    break;         
		case DATA_EXCLUDE_RANGE:
			if (nWidth==1)
		    	wsprintf(szBuf, "~%s 0X%02X 0X%02X ",
		    		g_range,
		     		m_busEv.dataValue1,
		     		m_busEv.dataValue2);
			else		     		
		    	wsprintf(szBuf, "~%s 0X%04X 0X%04X ",
		    		g_range,
		     		m_busEv.dataValue1,
		     		m_busEv.dataValue2);
		    break;         
		case DATA_WILD_CARD:
			StrFromValueMask(szBuf, m_busEv.dataValue1,
						m_busEv.dataValue2, nWidth*8, DATA_TYPE);
			break;
		case DATA_SINGLE:  
			if (nWidth==1)
				wsprintf(szBuf, "0X%02X ", m_busEv.dataValue1);
			else
				wsprintf(szBuf, "0X%04X ", m_busEv.dataValue1);
			break;
	}
}

void CBusEvent::SetStatus(int &nIndexHere)
{        
	int nResult;
	
	char* pCur = strchr(m_pArgPoint[nIndexHere], '<');
	
	if (!pCur) return;
	
	char *pEndCur = pCur;
	
	char cTmp;
	
	do {
		pCur = pEndCur + 1;
		while(*pCur==' ') pCur++;
		
		pEndCur = strpbrk(pCur, " >");
	    
	    if (!pEndCur) break;
	    
		cTmp = *pEndCur;
	
		*pEndCur = '\0';
		
		nResult = IsStatus(pCur);
		
		*pEndCur = cTmp;
		
		if (nResult<0) break;
		
		m_tmpBusEv.statusValue |= nResult;
	}while(*pEndCur != '>');	
	
	nIndexHere++;
}

void CBusEvent::GetStatusStr(char* szBuf)
{
	if (m_busEv.statusValue==0){
		*szBuf = '\0';
		return;
	}
	
	wsprintf(szBuf, "Status <");
	
	if (m_busEv.statusValue & STATUS_S)
		strcat(szBuf, "S ");              
				
	if (m_busEv.statusValue & STATUS_R)
		strcat(szBuf, "R ");              

	if (m_busEv.statusValue & STATUS_W)
		strcat(szBuf, "W "); 
	
	strcpy(szBuf+strlen(szBuf)-1, ">");

	return;		
}

void CBusEvent::SetCount(int &nIndexHere)
{
	ASSERT(nIndexHere < m_nArgMax);
	
	WORD nValue;
	
	if (IsCount(m_pArgPoint[nIndexHere], nValue))
	{
		m_tmpBusEv.counter = nValue;
		nIndexHere++;
	}	  
}

void CBusEvent::GetCountStr(char* szBuf)
{
	ASSERT(szBuf != NULL);
	
	if (m_busEv.counter == 0){
		*szBuf = '\0';
		return;
	}
	
	wsprintf(szBuf, "Count 0X%04X", m_busEv.counter);
}

int CBusEvent::ClearFW()
{
	if (IsEpRunning())
		return TRACE_ICE_RUNNING;

	int nStatus = emuClrEvent(m_wID);   
	
	if (nStatus==ICE_OK)
	{
		m_nClearFlag = OP_CLEAR;
		ResetContents(&m_busEv);
	}
	
	return nStatus;
}

int CBusEvent::SetFW()
{
	if (IsEpRunning())
		return TRACE_ICE_RUNNING;

	BUS_EVENT tmpEvent;
	
	memcpy(&tmpEvent, &m_tmpBusEv, sizeof(BUS_EVENT));
	
	SimplifySet();	
	
	BOOL bCounterMod = FALSE;
	if (m_tmpBusEv.counter > 0)
	{
		m_tmpBusEv.counter --;
		bCounterMod = TRUE;
	}
	
	int nStatus = emuSetEvent(m_wID, &m_tmpBusEv);   
	if (bCounterMod) m_tmpBusEv.counter ++;
	
	if (nStatus==ICE_OK)
	{
		m_nClearFlag = OP_SET;
		memcpy(&m_busEv, &tmpEvent, sizeof(BUS_EVENT));
	}  
	
	return nStatus;
}
	
void CBusEvent::SimplifySet()
{             
//    int nOptimize = 0;
    
//    enum { ADDR_OPTIMIZE = 1, DATA_OPTIMIZE = 2, STATUS_OPTIMIZE = 4};

	m_tmpBusEv.statusValue = 0;
		
	if (m_tmpBusEv.addrType == ADDR_WILD_CARD)
	{
		if (m_tmpBusEv.addrValue[1] == 0x3ffff)
		{
//			nOptimize |= ADDR_OPTIMIZE;
			SetAddrType(ADDR_NOT_SET);  
		}
		else if (m_tmpBusEv.addrValue[1] == 0)
		{
			SetAddrType(ADDR_GROUP);
			m_tmpBusEv.addrCount = 1;
		}
	}

/*	
	if ((m_tmpBusEv.dataType & 0x7f) == DATA_WILD_CARD)
	{
		if (m_tmpBusEv.dataValue2 == 0)
			SetDataType(DATA_SINGLE);
		else
		{	
			if (m_tmpBusEv.dataType & 0x80) // word data
			{
				if (m_tmpBusEv.dataValue2 == 0xffff)
					m_tmpBusEv.dataType = DATA_NOT_SET;
			}
			else if (m_tmpBusEv.dataValue2 == 0xff)// byte data
				m_tmpBusEv.dataType = DATA_NOT_SET;
		}									
	}   
*/
	
/*	if (IsEqualNotSet(m_tmpBusEv))
	{
		SetAddrType(ADDR_WILD_CARD);      
		m_tmpBusEv.addrValue[0] = 0;
		m_tmpBusEv.addrValue[1] = 0x3ffff;  
	}
*/	
}

BOOL CBusEvent::IsEqualNotSet(BUS_EVENT& busEvent)
{
	if (busEvent.addrType == ADDR_NOT_SET
		&& busEvent.dataType == DATA_NOT_SET)
		return TRUE;
	
	else return FALSE;
}
		
void CBusEvent::SetByShell()
{
	int nStatus = SetFW();
    
	if (nStatus==ICE_OK)
	{
		wsprintf(m_strDisplay.GetBuffer(60), "EV%1u %s",
				m_wID, g_set_success);
		m_strDisplay.ReleaseBuffer();
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}		

int  CBusEvent::SetByWin(BOOL bClearFlag, BUS_EVENT evData)
{
	if (bClearFlag)             
	{
		return ClearFW();
	}
	else
	{
		memcpy(&m_tmpBusEv, &evData, sizeof(BUS_EVENT));
		return SetFW();
	}
}

BOOL CBusEvent::DumpEvent(BOOL& bClearFlag, BUS_EVENT& evData)
{
	if (m_nClearFlag == OP_CLEAR)
		bClearFlag = TRUE;
	else
		bClearFlag = FALSE;

	memcpy(&evData, &m_busEv, sizeof(BUS_EVENT));
	
	return TRUE;
}

void CBusEvent::Clear()
{
	int nStatus = ClearFW();
	
	if (nStatus == ICE_OK)
	{                 
		wsprintf(m_strDisplay.GetBuffer(60), "Ev%1u %s",
				m_wID, g_clear_success);
		m_strDisplay.ReleaseBuffer();
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}

// show event in shell
void CBusEvent::ShowToShell()
{
	char szTemp[200];
	                    
	m_strDisplay.Empty();
	
	wsprintf(szTemp, "EV%u ", m_wID);
	m_strDisplay += szTemp;     
	
	if (m_nClearFlag == OP_CLEAR)     
	{
		m_strDisplay += g_is_clear;
	}
	else{
		GetAddrStr(szTemp);
		m_strDisplay += szTemp;
	
		GetDataStr(szTemp);	
		m_strDisplay += szTemp;
	
//		GetStatusStr(szTemp);
//		m_strDisplay += szTemp;
	
		GetCountStr(szTemp);   
		m_strDisplay += szTemp;
	}	
	
	CTraceBase::ShowToShell();
}                        

BOOL CBusEvent::Init()
{
	if (!CTraceBase::Init()) return FALSE;
	
	ResetContents(&m_busEv);
	ResetContents(&m_tmpBusEv);           
//	if (emuClrEvent(m_wID) != ICE_OK) return FALSE;
	m_nClearFlag = OP_CLEAR;	
	return TRUE;
}

void CBusEvent::ResetTmpData()
{
	ResetContents(&m_tmpBusEv);
}

void CBusEvent::ResetContents(void* pEvent)
{
	memset(pEvent, 0, sizeof(BUS_EVENT));
}

void CBusEvent::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CBusEvent::* myFunc) ();
	
	myFunc = CBusEvent::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsKeyword(m_pArgPoint[nIndexHere], g_address))
		{
			SetAddr(++nIndexHere);
			myFunc = CBusEvent::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_data))
		{
			SetData(++nIndexHere);
			myFunc = CBusEvent::SetByShell;
		}
//		else if(IsKeyword(m_pArgPoint[nIndexHere], g_status))
//		{
//			SetStatus(++nIndexHere);
//			myFunc = CBusEvent::SetByShell;
//		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_count))
		{
			SetCount(++nIndexHere);
			myFunc = CBusEvent::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere++], g_clear))
		{
			myFunc = CBusEvent::Clear;
			break; 
		}  
	}
	
	(this->*myFunc) ();
}

BOOL CBusEvent::RestoreSet()
{
	int nResult;
	if (m_nClearFlag == OP_CLEAR)
		nResult = emuClrEvent(m_wID);
	else nResult = emuSetEvent(m_wID, &m_busEv);
	
	return (nResult == ICE_OK) ? TRUE : FALSE;
}
			
/****************************************************************************
**	class CExtEvent
**  class for external event, such as event 3
**	Coding from: Apr. 28
**	Finish date:
****************************************************************************/

CExtEvent::CExtEvent()
{
	m_wID = 3;
}

CExtEvent::CExtEvent(WORD wEventID)
{   
	m_wID = wEventID;
}

	
CExtEvent::~CExtEvent()
{           
}

void CExtEvent::Serialize(CArchive& ar)
{
    CTraceBase::Serialize(ar);
    
    if(ar.IsStoring()){
        ar << m_wID << (WORD)m_nStatus;
    }
    else{     
    	WORD wStatus;
        ar >> m_wID >> wStatus;
        m_nStatus = (int)wStatus;
    }
}

BOOL CExtEvent::Init()
{
	if (!CTraceBase::Init()) return FALSE;
	ResetContents(&m_nStatus);
	ResetContents(&m_nTmpStatus);         
	
//	if (emuSetExtEvent((WORD)m_nTmpStatus) != ICE_OK)
//		return FALSE;
	m_nClearFlag = OP_SET;		
	return TRUE;		
}

void CExtEvent::ResetTmpData()
{
	ResetContents(&m_nTmpStatus);
}

void CExtEvent::ResetContents(void* pEvent)
{
	*((int*)pEvent) = EV_LOW;
}

void CExtEvent::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CExtEvent::* myFunc) ();
	
	myFunc = CExtEvent::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsKeyword(m_pArgPoint[nIndexHere], g_high))
		{
			m_nTmpStatus = EV_HIGH;
			myFunc = CExtEvent::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_low))
		{
			m_nTmpStatus = EV_LOW;
			myFunc = CExtEvent::SetByShell;
		}       
		
		nIndexHere++;
	}
    
    (this->*myFunc) ();
}

void CExtEvent::ShowToShell()
{
    m_strDisplay.Empty();
    
    char szBuf[40];

	wsprintf(szBuf, "Ev%u ", m_wID);
	    
	switch(m_nStatus){
		case EV_LOW:
			strcat(szBuf, g_low);
			break;
		case EV_HIGH:
			strcat(szBuf, g_high);
			break;
		default:
			ASSERT(0);
	}
	
	m_strDisplay = szBuf;
	
	CTraceBase::ShowToShell();
}

int  CExtEvent::SetFW()
{
	if (IsEpRunning())
		return TRACE_ICE_RUNNING;
	 
	int nStatus = emuSetExtEvent((WORD)m_nTmpStatus);
	
	if (nStatus == ICE_OK)
	{                     
		m_nClearFlag = OP_SET;
		
		m_nStatus = m_nTmpStatus;
	}
	
	return nStatus;
}
	
void CExtEvent::SetByShell()
{   
	int nStatus = SetFW();
	
	if (nStatus == ICE_OK)
	{                     
		wsprintf(m_strDisplay.GetBuffer(60), "EV%1u %s",
				m_wID, g_set_success);
		m_strDisplay.ReleaseBuffer();             
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}		

STATUS CExtEvent::SetByWin(WORD wStatus)
{                                    
	m_nTmpStatus = wStatus;
	
	return SetFW();
}

BOOL CExtEvent::DumpEvent(WORD& wStatus)
{
	wStatus = (WORD)m_nStatus;
	
	return TRUE;
}

BOOL CExtEvent::RestoreSet()
{
	int nResult = emuSetExtEvent((WORD)m_nStatus);
	
	return (nResult == ICE_OK) ? TRUE : FALSE;
}

/****************************************************************************
**	class CLevel
**  class for level
**	Coding from: Apr. 28
**	Finish date:
****************************************************************************/
CLevel::CLevel()
{   
}

CLevel::CLevel(WORD wLevelID)
{   
	m_wID = wLevelID;
}

	
CLevel::~CLevel()
{           
}

void CLevel::Serialize(CArchive& ar)
{
    CTraceBase::Serialize(ar);
    
    if(ar.IsStoring()){
        ar << m_wID;
        ar.Write(&m_level, sizeof(TRIGGER_LEVEL));
    }
    else{
        ar >> m_wID;
        ar.Read(&m_level, sizeof(TRIGGER_LEVEL));
    }
}

BOOL CLevel::Init()
{
	if (!CTraceBase::Init()) return FALSE;
	ResetContents(&m_level);
	ResetContents(&m_tmpLevel);           
	
//	if (emuSetTrigLevel(m_wID, &m_level) != ICE_OK) 
//		return FALSE;
	m_nClearFlag = OP_SET;		
	return TRUE;
}

void CLevel::ResetTmpData()
{
	memcpy(&m_tmpLevel, &m_level, sizeof(TRIGGER_LEVEL));
}

void CLevel::ResetContents(void* pData)
{       
	TRIGGER_LEVEL *pLevel = (TRIGGER_LEVEL*)pData;
	
	pLevel->traceFlag = TRACE_ON;
	pLevel->timerFlag = TIMER_ON;
	pLevel->dwCond = g_levelCond[ALL_EVENT].dwCond;
}

BOOL CLevel::IsEventID(const char* szBuf, WORD& wID)
{
	ASSERT(szBuf);
	
	if (strlen(szBuf) != 3) return FALSE;
	
	if (strnicmp(szBuf, g_event, 2) != 0) return FALSE;
	
	// first two characters are "EV"
	wID = (WORD)(szBuf[2] - '0');
	
	if ((wID>0) && (wID<=3)) return TRUE;
	
	return FALSE;	
}
 
void CLevel::GetEventLogicStr(char* szBuf)
{
	for (int i=0; i<ARRAYCOUNT(g_levelCond); i++)
	{
		if (m_level.dwCond == g_levelCond[i].dwCond)
		{
			strcpy(szBuf, g_levelCond[i].szCond);
			return;
		}
	}
	szBuf[0] = '\0';	
}

void CLevel::SetEventLogic(int& nIndexHere)
{                                                                    
	WORD wEvID;
	
	DWORD dwCond;
	
	VERIFY(IsEventID(m_pArgPoint[nIndexHere++], wEvID));
	dwCond = g_levelCond[wEvID-1].dwCond;
	
	while(nIndexHere < m_nArgMax){
		if (IsKeyword(m_pArgPoint[nIndexHere], g_or))
		{
			VERIFY(IsEventID(m_pArgPoint[++nIndexHere], wEvID));
			dwCond |= g_levelCond[wEvID-1].dwCond;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_and))
		{
			VERIFY(IsEventID(m_pArgPoint[++nIndexHere], wEvID));
			dwCond &= g_levelCond[wEvID-1].dwCond;
		}         
		else break;
		         		nIndexHere++;
	}
	
	m_tmpLevel.dwCond = dwCond;		
}

void CLevel::GetTraceStatusStr(char* szBuf)
{                  
	switch(m_level.traceFlag){
		case TRACE_NOT_SET:
			szBuf[0] = '\0';
			break;
		case TRACE_ON:
			wsprintf(szBuf,"%s %s ", g_trace, g_on);
			break;
		case TRACE_OFF:
			wsprintf(szBuf,"%s %s ", g_trace, g_off);
			break;
		default: ASSERT(0);			
	}
}

void CLevel::SetTraceStatus(int& nIndexHere)
{
	ASSERT(nIndexHere < m_nArgMax);
	
	if (IsKeyword(m_pArgPoint[nIndexHere], g_on))
	{
		m_tmpLevel.traceFlag = TRACE_ON;
		nIndexHere++;
	}                
	else if (IsKeyword(m_pArgPoint[nIndexHere], g_off))
	{
		m_tmpLevel.traceFlag = TRACE_OFF;
		nIndexHere++;
	}  
	else ASSERT(0);
}

void CLevel::GetTimerStatusStr(char* szBuf)
{                  
	switch(m_level.timerFlag){
		case TIMER_NOT_SET:
			szBuf[0] = '\0';
			break;
		case TIMER_ON:
			wsprintf(szBuf,"%s %s ", g_timer, g_on);
			break;
		case TIMER_OFF:
			wsprintf(szBuf,"%s %s ", g_timer, g_off);
			break;
		default: ASSERT(0);			
	}
}

void CLevel::SetTimerStatus(int& nIndexHere)
{
	ASSERT(nIndexHere < m_nArgMax);
	
	if (IsKeyword(m_pArgPoint[nIndexHere], g_on))
	{
		m_tmpLevel.timerFlag = TIMER_ON;
		nIndexHere++;
	}                
	else if (IsKeyword(m_pArgPoint[nIndexHere], g_off))
	{
		m_tmpLevel.timerFlag = TIMER_OFF;
		nIndexHere++;
	}  
	else ASSERT(0);
}

void CLevel::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CLevel::* myFunc) ();
	
	myFunc = CLevel::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsContainKeyword(m_pArgPoint[nIndexHere], g_event))
		{// not inc nIndexHere
			SetEventLogic(nIndexHere);
			myFunc = CLevel::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_trace))
		{
			SetTraceStatus(++nIndexHere);
			myFunc = CLevel::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_timer))
		{
			SetTimerStatus(++nIndexHere);
			myFunc = CLevel::SetByShell;
		}
	}
    
    (this->*myFunc) ();
}

void CLevel::ShowToShell()
{
    m_strDisplay.Empty();
    
    char szBuf[40];

	wsprintf(szBuf, "%s%1u ", g_level, m_wID);
	m_strDisplay = szBuf;
	
	GetEventLogicStr(szBuf);
	m_strDisplay += szBuf;
	
//	GetTraceStatusStr(szBuf);
//	m_strDisplay += szBuf;
	
//	GetTimerStatusStr(szBuf);
//	m_strDisplay += szBuf;
	
	CTraceBase::ShowToShell();
}

int  CLevel::SetFW()
{
	if (IsEpRunning())
		return TRACE_ICE_RUNNING;
	 
	int nStatus = emuSetTrigLevel(m_wID, &m_tmpLevel);
	
	if (nStatus == ICE_OK)
	{                  
		m_nClearFlag = OP_SET;
		
		memcpy(&m_level, &m_tmpLevel, sizeof(TRIGGER_LEVEL));
	}
	return nStatus;
}                               

void CLevel::SetByShell()
{   
	int nStatus = SetFW();
		
	if (nStatus == ICE_OK)
	{                  
		wsprintf(m_strDisplay.GetBuffer(60), "LV%1u %s",
				m_wID, g_set_success);
		m_strDisplay.ReleaseBuffer();             
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}	

int CLevel::SetByWin(TRIGGER_LEVEL lvData)
{
	memcpy(&m_tmpLevel, &lvData, sizeof(TRIGGER_LEVEL));
	
	return SetFW();
}

BOOL CLevel::DumpLevel(TRIGGER_LEVEL& lvData)
{
	memcpy(&lvData, &m_level, sizeof(TRIGGER_LEVEL));
	
	return TRUE;
}

BOOL CLevel::RestoreSet()
{
	int nResult = emuSetTrigLevel(m_wID, &m_level);
	
	return (nResult == ICE_OK) ? TRUE : FALSE;
}

/****************************************************************************
**	class CTrigger
**  class for trigger
**	Coding from: Apr. 28
**	Finish date:
****************************************************************************/


CTrigger::CTrigger()
{   
}

	
CTrigger::~CTrigger()
{           
}

void CTrigger::Serialize(CArchive& ar)
{
    CTraceBase::Serialize(ar);
    
    if(ar.IsStoring()){
        ar << m_nStatus;
        ar.Write(&m_trig, sizeof(TRIGGER_LOGIC));
    }
    else{      
    	WORD wStatus;
        ar >> wStatus;
        m_nStatus = (int)wStatus;
        ar.Read(&m_trig, sizeof(TRIGGER_LOGIC));
    }
}

BOOL CTrigger::Init()
{
	if (!CTraceBase::Init()) return FALSE;
	
	m_nStatus = TRIGGER_OFF;
	ResetContents(&m_trig);
	
	m_nTmpStatus = TRIGGER_OFF;
	ResetContents(&m_tmpTrig);            
	
	if (emuSetTriggerStatus((BYTE)m_nStatus) != ICE_OK) return FALSE;
//	if (emuSetTrigLogic(&m_trig) != ICE_OK) return FALSE;
	
	m_nClearFlag = OP_SET;
	
	return TRUE;
}

void CTrigger::ResetTmpData()
{                              
	m_nTmpStatus = m_nStatus;
	
	memcpy(&m_tmpTrig, &m_trig, sizeof(TRIGGER_LOGIC));
	m_tmpTrig.runFlag = NOT_RUN;
}

void CTrigger::ResetContents(void* pData)
{       
	TRIGGER_LOGIC *pTrigger = (TRIGGER_LOGIC*)pData;
	
	pTrigger->trigFlag = 0;
	pTrigger->runFlag = NOT_RUN;
	pTrigger->delayCount = 0;
	pTrigger->levelCount = 1;
	pTrigger->levelID[0] = LV1;	
}

void CTrigger::GetRunFlagStr(char* szBuf)
{
	switch(m_trig.runFlag){
		case NOT_RUN:
			szBuf[0] = '\0';
			break;
		case RUN: 
			wsprintf(szBuf, "%s ", g_run);
			break;
		default: ASSERT(0);
	}
}

BOOL CTrigger::IsLevelID(const char* szBuf, WORD& wID)
{
	ASSERT(szBuf);
	
	if (strlen(szBuf) != 3) return FALSE;
	
	if (strnicmp(szBuf, g_level, 2) != 0) return FALSE;
	
	// first two characters are "EV"
	wID = (WORD)(szBuf[2] - '0');
	
	if ((wID>0) && (wID<=2)) return TRUE;
	
	return FALSE;	
}

void CTrigger::SetLevel(int& nIndexHere)
{                 
	WORD wID;
	
	IsLevelID(m_pArgPoint[nIndexHere++], wID);
	
	m_tmpTrig.levelCount = 1;
	m_tmpTrig.levelID[0] = wID;
	
	if (nIndexHere<m_nArgMax && IsKeyword(m_pArgPoint[nIndexHere], g_then))
	{
		IsLevelID(m_pArgPoint[++nIndexHere], wID);
		m_tmpTrig.levelCount++;
		m_tmpTrig.levelID[1] = wID;
		nIndexHere++;
	}
}

void CTrigger::GetLevelStr(char* szBuf)
{
	switch(m_trig.levelCount){
		case 1:
			wsprintf(szBuf, "%s%d ", g_level, 
				m_trig.levelID[0]);
			break;
		case 2:
			wsprintf(szBuf, "%s%1u %s %s%1u ", g_level, m_trig.levelID[0],
					g_then, g_level, m_trig.levelID[1]);
			break;
		default:
			szBuf[0] ='\0';
	}
}

void CTrigger::SetDelay(int &nIndexHere)
{
	m_tmpTrig.trigFlag = DELAY;
	
	if (isNum(m_pArgPoint[nIndexHere])){
		m_tmpTrig.delayCount = strtoul(m_pArgPoint[nIndexHere++], NULL, 16);
	}
}

void CTrigger::GetPropertyStr(char* szBuf)
{
	switch(m_trig.trigFlag){
		case DELAY:        
			wsprintf(szBuf, "%s %04lX ", g_delay, m_trig.delayCount);
			break;
		case FORWARD:
			wsprintf(szBuf, "%s ", g_forward);
			break;
		case BACKWARD:
			wsprintf(szBuf, "%s ", g_backward);
			break;
		case CENTER:
			wsprintf(szBuf, "%s ", g_center);
			break;
		default: ASSERT(0);
	}
}                 

void CTrigger::ShowToShell()
{
    m_strDisplay.Empty();
    
    char szBuf[80];

	m_strDisplay = g_trigger;
	m_strDisplay += ' ';
	
	GetRunFlagStr(szBuf);
	m_strDisplay += szBuf;
	
	GetLevelStr(szBuf);
	m_strDisplay += szBuf;
	
	GetPropertyStr(szBuf);
	m_strDisplay += szBuf;
	
	CTraceBase::ShowToShell(); 
	
	m_strDisplay.Empty();
	m_strDisplay = g_trigger;
	switch(m_nStatus){
		case TRIGGER_OFF:
			wsprintf(szBuf, " is %s", g_off);
			break;
		case TRIGGER_ON:
			wsprintf(szBuf, " is %s", g_on);
			break;                  
		default:
			ASSERT(0);
	}
	m_strDisplay += szBuf;
		
	CTraceBase::ShowToShell();			
}

STATUS CTrigger::SetFW()
{
	if (IsEpRunning())
	{ 
		return TRACE_ICE_RUNNING;
	}
	 
	int nStatus = emuSetTrigLogic(&m_tmpTrig);
	
	if (nStatus == ICE_OK)
	{                    
		m_nClearFlag = OP_SET;
		memcpy(&m_trig, &m_tmpTrig, sizeof(TRIGGER_LOGIC));
	}
	
	return nStatus;
}
	
void CTrigger::SetByShell()
{   
	int nStatus = SetFW();
	
	if (nStatus == ICE_OK)
	{
		m_strDisplay.Empty();	
		wsprintf(m_strDisplay.GetBuffer(60), "%s %s",
				g_trigger, g_set_success);
		m_strDisplay.ReleaseBuffer();             
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}	

int CTrigger::SetByWin(TRIGGER_LOGIC trigData)
{
	memcpy(&m_tmpTrig, &trigData, sizeof(TRIGGER_LOGIC));
	return SetFW();
}

BOOL CTrigger::DumpTrig(TRIGGER_LOGIC& trigData)
{
	memcpy(&trigData, &m_trig, sizeof(TRIGGER_LOGIC));
	
	return TRUE;
}

int CTrigger::SetFWStatus()
{
	if (IsEpRunning())
	{ 
		return TRACE_ICE_RUNNING;
	}
	 
	int nStatus = emuSetTriggerStatus((BYTE)m_nTmpStatus);
	
	if (nStatus == ICE_OK)
	{
		m_nStatus = m_nTmpStatus;
	}
	
	return nStatus;
}

void CTrigger::SetTrigStatusByShell()
{
	int nStatus = SetFWStatus();			
	
	if (nStatus == ICE_OK)
	{
		wsprintf(m_strDisplay.GetBuffer(60), "%s %s",
				g_trigger, g_set_success);
		m_strDisplay.ReleaseBuffer();             
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus); 
}
		
int CTrigger::SetStatusByWin(BOOL bTrigStatus)
{
	if (bTrigStatus) m_nTmpStatus = TRIGGER_ON;
	else m_nTmpStatus = TRIGGER_OFF;
	
	return SetFWStatus();
}

BOOL CTrigger::DumpTrigStatus(BOOL& bTrigStatus)
{
	if (m_nStatus == TRIGGER_ON) bTrigStatus = TRUE;
	else bTrigStatus = FALSE;   
	
	return TRUE;
}

void CTrigger::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CTrigger::* myFunc) ();
	
	myFunc = CTrigger::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsKeyword(m_pArgPoint[nIndexHere], g_run))
		{// RUN
			nIndexHere++;
			m_tmpTrig.runFlag = RUN;
			myFunc = CTrigger::SetByShell;
		}
		else if(IsContainKeyword(m_pArgPoint[nIndexHere], g_level))
		{ // level logic
			SetLevel(nIndexHere);
			myFunc = CTrigger::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_delay))
		{   // delay
			SetDelay(++nIndexHere);
			myFunc = CTrigger::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_forward))
		{   // forward
			nIndexHere++;
			m_tmpTrig.trigFlag = FORWARD;
			myFunc = CTrigger::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_backward))
		{   // backward
			nIndexHere++;
			m_tmpTrig.trigFlag = BACKWARD;
			myFunc = CTrigger::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_center))
		{   // center
			nIndexHere++;
			m_tmpTrig.trigFlag = CENTER;
			myFunc = CTrigger::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_off))
		{   // trigger off
			nIndexHere++;
			m_nTmpStatus = TRIGGER_OFF;
			myFunc = CTrigger::SetTrigStatusByShell;
			break;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_on))
		{   // trigger on
			nIndexHere++;
			m_nTmpStatus = TRIGGER_ON;
			myFunc = CTrigger::SetTrigStatusByShell;
			break;
		}
	}
    
    (this->*myFunc) ();
} 

CTrigger::RestoreSet()
{
	if (emuSetTriggerStatus((BYTE)m_nStatus) != ICE_OK) return FALSE;
	if (emuSetTrigLogic(&m_trig) != ICE_OK) return FALSE;
	
	return TRUE;
}

/****************************************************************************
**	class CQualify
**  class for qualify
**  qualify is similar to event, but their stucture is different
**  I have to redefine each routine
**	Coding from: Apr. 28
**	Finish date:
****************************************************************************/


CQualify::CQualify()
{   
}
	
CQualify::~CQualify()
{           
}

void CQualify::Serialize(CArchive& ar)
{
    CTraceBase::Serialize(ar);
    
    if(ar.IsStoring()){
         ar.Write(&m_qualify, sizeof(QUALIFY_INFO));
    }
    else{
        ar.Read(&m_qualify, sizeof(QUALIFY_INFO));
    }
}

BOOL CQualify::Init()
{
	if (!CTraceBase::Init()) return FALSE;
	
	ResetContents(&m_qualify);
	ResetContents(&m_tmpQualify);         
	
//	if (emuClearQualify() != ICE_OK) return FALSE;
	
	m_nClearFlag = OP_CLEAR;
	
	return TRUE;
}

void CQualify::ResetTmpData()
{                              
	memset(&m_tmpQualify, 0, sizeof(QUALIFY_INFO));
}

void CQualify::ResetContents(void* pData)
{       
	memset(pData, 0, sizeof(QUALIFY_INFO));	
}

void CQualify::WildCardAddr(char *pInput)
{ 
	ASSERT( pInput );

	DWORD dwValue, dwMask;
		
	WildCard(pInput, dwValue, dwMask, ADDR_TYPE);
	
	SetAddrType(ADDR_WILD_CARD);
	
	m_tmpQualify.addrValue[0] = dwValue;
	m_tmpQualify.addrValue[1] = dwMask;
}

void CQualify::WildCardData(char *pInput)
{
	ASSERT( pInput );

	DWORD dwValue, dwMask;
		
	WildCard(pInput, dwValue, dwMask, DATA_TYPE);
	
	SetDataType(DATA_WILD_CARD);
	
	m_tmpQualify.dataValue1 = (WORD)dwValue;
	m_tmpQualify.dataValue2 = (WORD)dwMask;
}

// because there are some differences in event structure in each project 
// I try to reduce their effects.
void CQualify::SetAddrType(int nType)
{               
	m_tmpQualify.addrType = (BYTE)nType;
}

int CQualify::GetAddrType()
{
	return m_qualify.addrType;
}

void CQualify::SetDataWidth(int nByteNum)
{
	if (nByteNum==1){ // 8 bits
		m_tmpQualify.dataType &= 0x7f;
	}
	else { // 16 bits
		m_tmpQualify.dataType |= 0x80;
	}
}

int CQualify::GetDataWidth()
{
	return (m_qualify.dataType & 0x80)? 2 : 1;
}
                            
void CQualify::SetDataType(int nType)
{
	m_tmpQualify.dataType &= 0x80;
	m_tmpQualify.dataType |= nType;
}

int CQualify::GetDataType()
{
	return m_qualify.dataType & 0x7f;
}
                            
void CQualify::SetAddr(int& nIndexHere)
{ 
	ASSERT(nIndexHere < m_nArgMax);

	DWORD dwAddrVal;
	
	// first search if it is a range address
	if (IsKeyword(g_range, m_pArgPoint[nIndexHere]))
	{
		SetAddrType(ADDR_RANGE);
		
		nIndexHere++;
	    ASSERT(nIndexHere < m_nArgMax);

	    if (IsPAddr(m_pArgPoint[nIndexHere], dwAddrVal))
   			m_tmpQualify.addrValue[0] = dwAddrVal;

	    nIndexHere++;
    	ASSERT(nIndexHere < m_nArgMax);

	    if (IsPAddr(m_pArgPoint[nIndexHere], dwAddrVal))
	    {
   			m_tmpQualify.addrValue[1] = dwAddrVal;
   		    m_tmpQualify.addrValue[1] |= ((DWORD)GetAddrBank(m_tmpQualify.addrValue[0]))
   		    				<< 16;
   		}
    	
    	nIndexHere++;
    	m_tmpQualify.addrCount = 2;
    }        
	else if(IsWildCard(m_pArgPoint[nIndexHere]))
    { //for wild card address  
    	WildCardAddr(m_pArgPoint[nIndexHere]);       
    	nIndexHere++;
    }
  	else if (IsPAddr(m_pArgPoint[nIndexHere], dwAddrVal)) 
   {  //for maximum ten addresses
	    SetAddrType(ADDR_GROUP); 
	    
	    BYTE nNum = 0;
        
        char* pCur = m_pArgPoint[nIndexHere];

		while(*pCur == ' ' || *pCur=='<')
   			pCur++; // bypass blank
        
        while(*pCur && IsPAddr(pCur, dwAddrVal) && nNum<10)
        {
       		m_tmpQualify.addrValue[nNum++] = dwAddrVal;
       		pCur = strchr(pCur, ' ');
       		
       		if (pCur != NULL)              
       			do{
        			pCur++; // bypass blank
        		}while(*pCur == ' ' || *pCur == '>');
        	else break;
        	
        }
        	
	    m_tmpQualify.addrCount = nNum;
	    nIndexHere++;
    }//if
	m_tmpQualify.filterFlag = FILTER_ON; 
}//function

void CQualify::GetAddrStr(char* szBuf)
{
	int nType = GetAddrType();
	
	if (nType == ADDR_NOT_SET)
	{
		*szBuf = '\0';
		return;
	}

	wsprintf(szBuf, "Address ");
	szBuf += strlen(szBuf);
		
	switch(nType)
	{
		case ADDR_RANGE:      
		    wsprintf(szBuf, "%s P%1d:%04lX P%1d:%04lX ",
		    	g_range,
		    	GetAddrBank(m_qualify.addrValue[0]),
		     	m_qualify.addrValue[0] & 0xffff,
		     	GetAddrBank(m_qualify.addrValue[1]),
		     	m_qualify.addrValue[1] & 0xffff);
		    break;         
		case ADDR_EXCLUDE_RANGE:
		    wsprintf(szBuf, "~%s P%1d:%04lX P%1d:%04lX ",
		    	g_range,
		    	GetAddrBank(m_qualify.addrValue[0]),
		     	m_qualify.addrValue[0] & 0xffff,
		     	GetAddrBank(m_qualify.addrValue[1]),
		     	m_qualify.addrValue[1] & 0xffff);
		    break;         
		case ADDR_WILD_CARD:
			StrFromValueMask(szBuf, m_qualify.addrValue[0],
						m_qualify.addrValue[1], 16, ADDR_TYPE);
			break;
		case ADDR_GROUP:       
			strcpy(szBuf, "<");
			szBuf += strlen(szBuf);
			
			for (int i=0; i<m_qualify.addrCount; i++)
			{
				wsprintf(szBuf, "P%1d:%04lX ", 
					GetAddrBank(m_qualify.addrValue[i]),
					m_qualify.addrValue[i] & 0xffff);
				szBuf += strlen(szBuf);
			}                                         
			strcpy(szBuf-1, "> ");
	}
}

void CQualify::SetData(int &nIndexHere)
{       
	ASSERT(nIndexHere < m_nArgMax);

	if (IsKeyword("WORD", m_pArgPoint[nIndexHere]))
		SetDataWidth(2);
	else 
		SetDataWidth(1);
	
	nIndexHere++;
    ASSERT(nIndexHere < m_nArgMax);
		
	WORD wDataVal;
	
	// first search if it is a range data
	if (IsKeyword(g_range, m_pArgPoint[nIndexHere]))
	{
		SetDataType(DATA_RANGE);
		
		nIndexHere++;
	    ASSERT(nIndexHere < m_nArgMax);

	    if (IsEventData(m_pArgPoint[nIndexHere], wDataVal))
   			m_tmpQualify.dataValue1 = wDataVal;

	    nIndexHere++;
    	ASSERT(nIndexHere < m_nArgMax);

	    if (IsEventData(m_pArgPoint[nIndexHere], wDataVal))
   			m_tmpQualify.dataValue2 = wDataVal;
    	
    	nIndexHere++;
    }        
	else if(IsWildCard(m_pArgPoint[nIndexHere]))
    { //for wild card data  
    	WildCardData(m_pArgPoint[nIndexHere]);       
    	nIndexHere++;
    }
    
    else if ( IsEventData(m_pArgPoint[nIndexHere], wDataVal) ) 
	{   //for one addresses
                                                        
		SetDataType(DATA_SINGLE);
	    m_tmpQualify.dataValue1 = wDataVal;
    	nIndexHere++;
    }//if

	m_tmpQualify.filterFlag = FILTER_ON; 
}

void CQualify::GetDataStr(char* szBuf)
{
	int nType = GetDataType();
	
	if (nType == DATA_NOT_SET)
	{
		*szBuf = '\0';
		return;
	}

	wsprintf(szBuf, "Datum ");
	szBuf += strlen(szBuf);

	int nWidth = GetDataWidth();	
	
	switch(nWidth){
		case 1:
			wsprintf(szBuf, "Byte ");
			break;
		case 2:
			wsprintf(szBuf, "Word ");
			break;
	}
	szBuf += strlen(szBuf);
	
	switch(nType)
	{
		case DATA_RANGE:       
			if (nWidth==1)
		    	wsprintf(szBuf, "%s 0X%02X 0X%02X ",
		    		g_range,
		     		m_qualify.dataValue1,
		     		m_qualify.dataValue2);
			else		     		
		    	wsprintf(szBuf, "%s 0X%04X 0X%04X ",
		    		g_range,
		     		m_qualify.dataValue1,
		     		m_qualify.dataValue2);
		    break;         
		case DATA_EXCLUDE_RANGE:
			if (nWidth==1)
		    	wsprintf(szBuf, "~%s 0X%02X 0X%02X ",
		    		g_range,
		     		m_qualify.dataValue1,
		     		m_qualify.dataValue2);
			else		     		
		    	wsprintf(szBuf, "~%s 0X%04X 0X%04X ",
		    		g_range,
		     		m_qualify.dataValue1,
		     		m_qualify.dataValue2);
		    break;         
		case DATA_WILD_CARD:
			StrFromValueMask(szBuf, m_qualify.dataValue1,
						m_qualify.dataValue2, nWidth*8, DATA_TYPE);
			break;
		case DATA_SINGLE:  
			if (nWidth==1)
				wsprintf(szBuf, "0X%02X ", m_qualify.dataValue1);
			else
				wsprintf(szBuf, "0X%04X ", m_qualify.dataValue1);
			break;
	}
}

void CQualify::SetStatus(int &nIndexHere)
{        
	int nResult;
	
	char* pCur = strchr(m_pArgPoint[nIndexHere], '<');
	
	if (!pCur) return;
	
	char *pEndCur = pCur;
	
	char cTmp;
	
	do {
		pCur = pEndCur + 1;
		while(*pCur==' ') pCur++;
		
		pEndCur = strpbrk(pCur, " >");
	    
	    if (!pEndCur) break;
	    
		cTmp = *pEndCur;
	
		*pEndCur = '\0';
		
		nResult = IsStatus(pCur);
		
		*pEndCur = cTmp;
		
		if (nResult<0) break;
		
		m_tmpQualify.statusValue |= nResult;
	}while(*pEndCur != '>');	
	
	m_tmpQualify.filterFlag = FILTER_ON; 

	nIndexHere++;
}

void CQualify::GetStatusStr(char* szBuf)
{
	if (m_qualify.statusValue==0){
		*szBuf = '\0';
		return;
	}
	
	wsprintf(szBuf, "Status <");
	
	if (m_qualify.statusValue & STATUS_S)
		strcat(szBuf, "S ");              
				
	if (m_qualify.statusValue & STATUS_R)
		strcat(szBuf, "R ");              

	if (m_qualify.statusValue & STATUS_W)
		strcat(szBuf, "W ");  
	
	if (m_qualify.statusValue & STATUS_AK)
		strcat(szBuf, "AK ");
	
	strcpy(szBuf+strlen(szBuf)-1, ">");

	return;		
}

STATUS CQualify::SetFW()
{
	if (IsEpRunning())
		return TRACE_ICE_RUNNING;
	
	QUALIFY_INFO tmpQualify;
	
	memcpy(&tmpQualify, &m_tmpQualify, sizeof(QUALIFY_INFO));

	SimplifySet();	                

	int nStatus;
	
	if (IsEqualNotSet(m_tmpQualify))
		nStatus = emuClearQualify();
	else
		nStatus = emuSetQualify(&m_tmpQualify);
	
	if (nStatus == ICE_OK)
	{                    
		m_nClearFlag = OP_SET;
		memcpy(&m_qualify, &tmpQualify, sizeof(QUALIFY_INFO));
	}
	
	return nStatus;
}

BOOL CQualify::IsEqualNotSet(QUALIFY& qualifyData)
{
	if (qualifyData.filterFlag == FILTER_OFF)
		return TRUE;

	if (qualifyData.addrType == ADDR_NOT_SET
		&& qualifyData.dataType == DATA_NOT_SET
		&& qualifyData.statusValue == STATUS_NOT_SET)
		return TRUE;
		
	return FALSE;		
}	
	
void CQualify::SimplifySet()
{             
	if (m_tmpQualify.addrType == ADDR_WILD_CARD)
	{
		if (m_tmpQualify.addrValue[1] == 0x3ffff)
			SetAddrType(ADDR_NOT_SET);
		else if (m_tmpQualify.addrValue[1] == 0)
		{
			SetAddrType(ADDR_GROUP);
			m_tmpQualify.addrCount = 1;
		}
	}

/*	
	if ((m_tmpQualify.dataType & 0x7f) == DATA_WILD_CARD)
	{
		if (m_tmpQualify.dataValue2 == 0)
			SetDataType(DATA_SINGLE);
		else
		{	
			if (m_tmpQualify.dataType & 0x80) // word data
			{
				if (m_tmpQualify.dataValue2 == 0xffff)
					m_tmpQualify.dataType = DATA_NOT_SET;
			}
			else if (m_tmpQualify.dataValue2 == 0xff)// byte data
				m_tmpQualify.dataType = DATA_NOT_SET;
		}									
	}       
*/
	
	if ((m_tmpQualify.statusValue & 0xf) == 0xf)
		m_tmpQualify.statusValue = STATUS_NOT_SET;
}

void CQualify::SetByShell()
{
	int nStatus = SetFW();
	
	if (nStatus == ICE_OK)
	{                    
		wsprintf(m_strDisplay.GetBuffer(60), "Qualify %s",
				g_set_success);
		m_strDisplay.ReleaseBuffer();
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}		

STATUS CQualify::SetByWin(QUALIFY_INFO qualifyData)
{
	memcpy(&m_tmpQualify, &qualifyData, sizeof(QUALIFY_INFO));
	return SetFW();
}

BOOL CQualify::DumpQualify(QUALIFY_INFO& qualifyData)
{
	if (m_nClearFlag == OP_CLEAR)
		memset(&qualifyData, 0, sizeof(QUALIFY_INFO));
	else	
		memcpy(&qualifyData, &m_qualify, sizeof(QUALIFY_INFO));
	return TRUE;
}

void CQualify::Clear()
{
	if (IsEpRunning())
	{
		DisplayErrorMessage(ER_GOFLY_ERR_MSG);
		return;
	}
	
	int nStatus = emuClearQualify();
	
	if (nStatus == ICE_OK)
	{               
		m_nClearFlag = OP_CLEAR;  
		ResetContents(&m_qualify);
		wsprintf(m_strDisplay.GetBuffer(60), "Qualify %s",
				g_clear_success);
		m_strDisplay.ReleaseBuffer();
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}

// show event in shell
void CQualify::ShowToShell()
{
	char szTemp[250];
	                    
	m_strDisplay.Empty();
	
	m_strDisplay = "Qualify ";

	if (m_nClearFlag == OP_CLEAR){
		m_strDisplay += g_is_clear;
	}
	else{	
		GetAddrStr(szTemp);
		m_strDisplay += szTemp;
	
		GetDataStr(szTemp);	
		m_strDisplay += szTemp;
	
		GetStatusStr(szTemp);
		m_strDisplay += szTemp;
	}
	
	CTraceBase::ShowToShell();
}                        

void CQualify::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CQualify::* myFunc) ();
	
	myFunc = CQualify::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsKeyword(m_pArgPoint[nIndexHere], g_address))
		{
			SetAddr(++nIndexHere);
			myFunc = CQualify::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_data))
		{
			SetData(++nIndexHere);
			myFunc = CQualify::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_status))
		{
			SetStatus(++nIndexHere);
			myFunc = CQualify::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere++], g_clear))
		{
			myFunc = CQualify::Clear;
			break; 
		}  
	}
	
	(this->*myFunc) ();
}

CQualify::RestoreSet()
{
	int nResult;
	
	if (m_nClearFlag == OP_CLEAR)
		nResult = emuClearQualify();
	else 
		nResult = emuSetQualify(&m_qualify);
					
	return (nResult==ICE_OK) ? TRUE : FALSE;
}

/****************************************************************************
**	class CControl
**  class for control
**	Coding from: May 5
**	Finish date:
****************************************************************************/


CControl::CControl()
{   
}

	
CControl::~CControl()
{           
}

BOOL CControl::Init()
{
	if (!CTraceBase::Init()) return FALSE;
//	ResetContents(&m_nStatus);
//	ResetContents(&m_nTmpStatus);         
	
//	if (emuSetControl(m_nStatus) != ICE_OK)
//		return FALSE;

	if (emuGetControl(&m_nStatus) != ICE_OK)
		return FALSE;

	m_nTmpStatus = m_nStatus;		
	m_nClearFlag = OP_SET;		

	return TRUE;		
}

BOOL CControl::GetCurStatus()
{
	return emuGetControl(&m_nStatus) == ICE_OK;
}
	
void CControl::ResetTmpData()
{
	GetCurStatus();
	m_nTmpStatus = m_nStatus;
}

void CControl::ResetContents(void* pData)
{       
//	memset(pData, 0, sizeof(int));
	memset(pData, 3, sizeof(int));
}

void CControl::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CControl::* myFunc) ();
	
	myFunc = CControl::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsKeyword(m_pArgPoint[nIndexHere], g_reset))
		{
			SetReset(++nIndexHere);
			myFunc = CControl::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_nmi))
		{
			SetNmi(++nIndexHere);
			myFunc = CControl::SetByShell;
		}
		else break;
	}
	
	(this->*myFunc) ();
}

void CControl::SetReset(int& nIndexHere)
{
	UniSetStatus(m_pArgPoint[nIndexHere], RESET);
	nIndexHere++;
}                

void CControl::GetResetStr(char* szBuf)
{                                     
	if (UniGetStatus(RESET))
		wsprintf(szBuf, "%s %s %s", g_reset, g_is, g_enable);
	else wsprintf(szBuf, "%s %s %s", g_reset, g_is, g_disable);
}

void CControl::GetNmiStr(char* szBuf)
{
	if (UniGetStatus(NMI))
		wsprintf(szBuf, "%s %s %s", g_nmi, g_is, g_enable);
	else wsprintf(szBuf, "%s %s %s", g_nmi, g_is, g_disable);
}
	
void CControl::SetNmi(int& nIndexHere)
{
	UniSetStatus(m_pArgPoint[nIndexHere], NMI);
	nIndexHere++;
}

void CControl::UniSetStatus(const char* szStr, int nStatusSite)
{
	if (IsKeyword(szStr, g_enable))
	{
		m_nTmpStatus |= 1<<nStatusSite;
	}
	else if (IsKeyword(szStr, g_disable))
	{
		m_nTmpStatus &= ~(1<<nStatusSite);
	}
}         

int CControl::UniGetStatus(int nStatusSite)
{
	if (m_nTmpStatus & (1<<nStatusSite))
		return ENABLE;
	else return DISABLE;
}

void CControl::SetByShell()
{
	if (IsEpRunning())
	{ 
		DisplayErrorMessage(ER_GOFLY_ERR_MSG);
		return;
	}
	 
	int nStatus = emuSetControl(m_nTmpStatus);
	
	if (nStatus == ICE_OK)
	{                    
		m_nClearFlag = OP_SET;
		m_nStatus = m_nTmpStatus;
		
		wsprintf(m_strDisplay.GetBuffer(60), "%s %s",
				g_control, g_set_success);
		m_strDisplay.ReleaseBuffer();
		CTraceBase::ShowToShell();
		return;
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}

// show control in shell
void CControl::ShowToShell()
{
	char szTemp[120];

// show reset status	                    
	m_strDisplay.Empty();    
	
	GetCurStatus();
	
	m_strDisplay = g_control;
	m_strDisplay += ' ';
	
	GetResetStr(szTemp);
	m_strDisplay += szTemp;
	
	CTraceBase::ShowToShell();

// show nmi status	
	m_strDisplay.Empty();
	
	m_strDisplay = g_control;
	m_strDisplay += ' ';
	
	GetNmiStr(szTemp);
	m_strDisplay += szTemp;
	
	CTraceBase::ShowToShell();
}                        

CControl::RestoreSet()
{
	if (emuSetControl((BYTE)m_nStatus) == ICE_OK)
		return TRUE;
	else
		return FALSE;
}

/****************************************************************************
**	class CInPort
**  class for inport
**	Coding from: May 5
**	Finish date:
****************************************************************************/

CInPort::CInPort()
{   
}

	
CInPort::~CInPort()
{           
}

void CInPort::ShellCmd(int nArgc, char** pszArgv)
{
	WORD nPort = (WORD) atoi(pszArgv[1]);
	ASSERT(nPort < 7);
	
	BYTE byPortVal;      
	char szBuf[30];
	
	int nStatus = emuInput(nPort, 1, 0, &byPortVal);
	
	if(nStatus != ICE_OK) DisplayErrorMessage(ER_ICE_OK+nStatus);
	else {      
		m_strDisplay.Empty();
		switch(nArgc){
			case 2:
				wsprintf(szBuf, "P%d value is ", nPort);
				m_strDisplay = szBuf; 
				
				StrFromValue(szBuf, byPortVal, 8);
				m_strDisplay += szBuf;
				m_strDisplay += 'B';
				break;
			case 3:
				wsprintf(szBuf, "P%d value is %02X", nPort, byPortVal);
				m_strDisplay = szBuf;
				break;
			case 4:
			{
				int nBit = atoi(pszArgv[3]);
				ASSERT(nBit<8);
				
				wsprintf(szBuf, "P%1d bit%1d is %1d", nPort, nBit,
					((byPortVal>>nBit) & 1) );
				m_strDisplay = szBuf;
			}
		}						
		CTraceBase::ShowToShell();
	}
}

/****************************************************************************
**	class COutPort
**  class for outport
**	Coding from: May 5
**	Finish date:
****************************************************************************/

COutPort::COutPort()
{   
}

	
COutPort::~COutPort()
{           
}

void COutPort::ShellCmd(int nArgc, char** pszArgv)
{
	ASSERT(nArgc==3);
	WORD nPort = (WORD) atoi(pszArgv[1]);
	ASSERT(nPort < 7);     
	
	BYTE byPortVal;      
	
	byPortVal = (BYTE)strtoul(pszArgv[2], NULL, 16);
	int nStatus = emuOutput(nPort, &byPortVal, 1, 0);
			
	if(nStatus != ICE_OK) DisplayErrorMessage(ER_ICE_OK+nStatus);
}
	
/****************************************************************************
**	class CCtlTrace
**  class for trace staus
**	Coding from: Apr. 29
**	Finish date:
****************************************************************************/

CCtlTrace::CCtlTrace()
{
	SetClearFlag();
}

CCtlTrace::~CCtlTrace()
{           
}

BOOL CCtlTrace::Init()
{
	if (!CTraceBase::Init()) return FALSE;
	ResetContents(&m_nStatus);
	ResetContents(&m_nTmpStatus);         
	
	if (emuSetTraceStatus((BYTE)m_nStatus) != ICE_OK)
		return FALSE;
//	m_nClearFlag = OP_SET;		
	return TRUE;
}

BOOL CCtlTrace::GetCurStatus()
{
	DWORD dwCpuStatus;
	if (emuGetCpuStatus(&dwCpuStatus) == ICE_OK)
	{
		m_nStatus = (dwCpuStatus & 0x8) ? TRACE_ON : TRACE_OFF;
		return TRUE;
	}
	else return FALSE;
}

void CCtlTrace::ResetTmpData()
{                  
	GetCurStatus();
	m_nTmpStatus = m_nStatus;
}

void CCtlTrace::ResetContents(void* pTrace)
{
	*((int*)pTrace) = TRACE_OFF;
}

void CCtlTrace::ShellCmd(int nArgc, char** pszArgv)
{
	CTraceBase::ShellCmd(nArgc, pszArgv); 
	
	void (CCtlTrace::* myFunc)();
	
	myFunc = CCtlTrace::ShowToShell;
	
	int nIndexHere = 1;  // command store in the first site
	
	while(nIndexHere < m_nArgMax){
		if(IsKeyword(m_pArgPoint[nIndexHere], g_on))
		{
			m_nTmpStatus = TRACE_ON;
			myFunc = CCtlTrace::SetByShell;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_off))
		{
			m_nTmpStatus = TRACE_OFF;
			myFunc = CCtlTrace::SetByShell;
		} 
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_clear))
		{
			m_nClearFlag = OP_CLEAR;
			myFunc = CCtlTrace::Clear;
		}      
		    
		nIndexHere++;
	}
    
    (this->*myFunc) ();
}                       

void CCtlTrace::Clear()
{
	m_nClearFlag = OP_CLEAR;     
	RefreshTraceWnd();
} 

void CCtlTrace::SetClearFlag()
{
	m_nClearFlag = OP_CLEAR;
}

void CCtlTrace::ValidBuffer()
{
	m_nClearFlag = OP_SET;
}

BOOL CCtlTrace::IsClear()
{
   return m_nClearFlag==OP_CLEAR;
}

void CCtlTrace::ShowToShell()
{
    m_strDisplay.Empty();
    
    char szBuf[80];

	
//	if (m_nClearFlag == OP_CLEAR)
//	{
//		m_strDisplay = g_trace_empty;
//	}
//	else    
	{
		m_strDisplay = "Trace ";
		
		GetCurStatus();

		switch(m_nStatus){
			case TRACE_OFF:
				strcpy(szBuf, g_off);
				break;
			case TRACE_ON:
				strcpy(szBuf, g_on);
				break;
			default:
				ASSERT(0); 
		}
	
		m_strDisplay += szBuf;
	}
		
	CTraceBase::ShowToShell();
}

int CCtlTrace::SetFW()
{
	int nStatus = emuSetTraceStatus((BYTE)m_nTmpStatus);
	
	if (nStatus == ICE_OK)
	{                     
		if (m_nTmpStatus==TRACE_ON && m_nStatus==TRACE_OFF)
		{// for trace on fly
			if (IsEpRunning()){
				ClearTraceCache();
				ValidBuffer();
			}
		}
				
		m_nStatus = m_nTmpStatus;
		SetTraceOn((BYTE)m_nStatus); // for John
	}
	return nStatus;
}
	
void CCtlTrace::SetByShell()
{   
	int nStatus = SetFW();
	
	if (nStatus == ICE_OK)
	{                     
		wsprintf(m_strDisplay.GetBuffer(60), "Trace %s",
				g_set_success);
		m_strDisplay.ReleaseBuffer();             
		CTraceBase::ShowToShell();  
	}		
	else DisplayErrorMessage(ER_ICE_OK+nStatus);
}		

STATUS CCtlTrace::SetByWin(BOOL trcData)
{
	 if (trcData) m_nTmpStatus = TRACE_ON;
	 else m_nTmpStatus = TRACE_OFF;
	 
	 return SetFW();
}

BOOL CCtlTrace::DumpStatus(BOOL& trcData)
{
//	GetCurStatus();
	
	if (m_nStatus==TRACE_ON) trcData = TRUE;
	else trcData = FALSE;  
	
	return TRUE;
}

BOOL CCtlTrace::RestoreSet()
{
	if (emuSetTraceStatus((BYTE)m_nStatus) == ICE_OK)
		return TRUE;
	else
		return FALSE;
}

/****************************************************************************
**	class CCtlShow
**  class for list trace buffer
**	Coding from: May. 19
**	Finish date:
****************************************************************************/

CTraceShow::CTraceShow()
{
}

CTraceShow::~CTraceShow()
{
}

int CTraceShow::GetStatus(BYTE byStatus)
{                        
   	int status =  (BYTE)((~byStatus) & 0xf);
	    	
   	switch(status){
   		case 1: 
   			status = STATUS_S;
   			break;
   		case 2:
   			status = STATUS_W;
   			break;
   		case 4:
   			status = STATUS_R;
   			break;
   		case 8:
   			status = STATUS_AK;
   			break;
   		default:
  // 			status = STATUS_NONE;
  			status = STATUS_S;
   	}            
   	
   	return status;
}

const char * CTraceShow::GetStatusStr(BYTE byStatus)
{
   	BYTE status = (BYTE)((~byStatus) & 0xf);
	    	
   	switch(status){
   		case 1: 
   			status = 0;
   			break;
   		case 2:
   			status = 1;
   			break;
   		case 4:
   			status = 2;
   			break;
   		case 8:
   			status = 3;
   			break;
   		default:
//   			status = 4;
			status = 0;
   	}      
   	
	return statusTbl[status];
}

const char* CTraceShow::GetSpareStr(BYTE byStatus)
{
//   	BYTE spare = (BYTE)((byStatus & 0xf0) >> 4);
	BYTE spare = (BYTE)(byStatus & 0x1f);

   	StrFromValue(m_pSpareBit, spare, 5); 
   	
   	return (const char*)m_pSpareBit;
}

void CTraceShow::DumpTraceBuf(char* szBuf, const TRACE_INFO* pTraceItem)
{
	ASSERT(pTraceItem != NULL);
	
   	if (pTraceItem->address & 0x80000000)// WORD data
	 	wsprintf(szBuf, " %04X   P%1d:%04lX  %04X     %2s        %5s",
        	pTraceItem->frameNo,    
           	GetAddrBank(pTraceItem->address),
           	pTraceItem->address & 0xffff,
           	pTraceItem->datum,
           	GetStatusStr(pTraceItem->status),
           	GetSpareStr(pTraceItem->bExternal));
    else 
   		wsprintf(szBuf, " %04X   P%1d:%04lX   %02X      %2s        %5s",
	        pTraceItem->frameNo,    
            GetAddrBank(pTraceItem->address),
            pTraceItem->address & 0xffff,
            (pTraceItem->address & 1) ? (BYTE)(pTraceItem->datum>>8) :
            	(BYTE)(pTraceItem->datum),
            GetStatusStr(pTraceItem->status),
            GetSpareStr(pTraceItem->bExternal));
}

BOOL CTraceShow::GetTraceDepth(BUFFER_DEPTH& bufferDep)
{
	if (IsEpRunning())
		SetTraceStatus(CCtlTrace::TRACE_OFF);
		
	int nErrorID = emuGetTraceDepth(m_wID,  &bufferDep);
	
	if (nErrorID != ICE_OK){
		DisplayErrorMessage(nErrorID);
		return FALSE;
	}
	
	return TRUE;
}

/****************************************************************************
**	class CCtlList
**  class for list trace buffer
**	Coding from: Apr. 29
**	Finish date:
****************************************************************************/

CCtlList::CCtlList()
{                              
	m_pTraceInfo = NULL;    
}

CCtlList::~CCtlList()
{                       
	if (m_pTraceInfo != NULL) delete [] m_pTraceInfo;      
	m_pTraceInfo = NULL;
}

void CCtlList::ResetTmpData()
{
	CQualify::ResetTmpData();
	m_dwStartList = m_depth.startFrame;
}

void CCtlList::ShellCmd(int nArgc, char** pszArgv)
{
	if (IsTraceClear())
	{
		m_strDisplay = g_trace_empty;
		CTraceBase::ShowToShell();
		return;
	}
				
	CTraceBase::ShellCmd(nArgc, pszArgv);

	GetTraceDepth(m_depth);
		
	if (m_depth.endFrame==0)
	{
		m_strDisplay = g_trace_empty;
		CTraceBase::ShowToShell();
		return;
	}	        
	
    void (CCtlList::* myFunc) ();//to decide asm or c or ... 
    myFunc = CCtlList::ListTrcDataToShell;
    
    int nIndexHere = 1;      
    
    DWORD wNum;
	while(nIndexHere < m_nArgMax){
		if (IsKeyword(m_pArgPoint[nIndexHere], g_number) )
		{
			m_strDisplay.Empty();
			wsprintf(m_strDisplay.GetBuffer(100), 
				g_trace_last_frame,
				m_depth.endFrame);
			m_strDisplay.ReleaseBuffer();
			CTraceBase::ShowToShell();  
			nIndexHere++;          
			myFunc = NULL;
			break;
		}
		else if(IsListFrame(m_pArgPoint[nIndexHere], wNum))
		{
			nIndexHere++;
			m_dwStartList = (wNum>m_depth.startFrame)? wNum : m_depth.startFrame;
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_address))
		{
			SetAddr(++nIndexHere);
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_data))
		{
			SetData(++nIndexHere);
		}
		else if(IsKeyword(m_pArgPoint[nIndexHere], g_status))
		{
			SetStatus(++nIndexHere);
		}
		else break;
	}
	
	if (myFunc) (this->*myFunc) (); 
	
	if (IsTraceClear()) return;
	
	char szBuf[256];
	
	if( !GetElapseTimeStr(szBuf) );
//		DisplayErrorMessage(ER_TRCSVR_GETETIMEERR);  

	m_strDisplay.Empty();
	m_strDisplay = "Elapse Time: ";
	m_strDisplay += szBuf;
	
	CTraceBase::ShowToShell();
}

	
void CCtlList::ListTrcDataToShell()
{
	if (m_dwStartList >= m_depth.endFrame)
	{
		m_strDisplay.Empty();
		wsprintf(m_strDisplay.GetBuffer(100), 
			g_trace_last_frame,
			m_depth.endFrame);
		m_strDisplay.ReleaseBuffer();
		CTraceBase::ShowToShell();  
		return;
	}    
	
	if (m_pTraceInfo == NULL) 
	{
		m_pTraceInfo = new TRACE_INFO[MAX_LIST_LINE];
		if (m_pTraceInfo == NULL) return;      
	}
	
	int nReadNum;    
	char szTmpShow[256];        
	
//	SaveCurTraceStatus();
//	SetTraceStatus(CCtlTrace::TRACE_OFF);
	
	BOOL bShowTitle = TRUE;	
	while(m_dwStartList < m_depth.endFrame)
	{
		if (TestKey(VK_ESCAPE)) break;
		
		if ((nReadNum=GetAbiFrame(m_dwStartList, m_depth.endFrame-1)) <0)
			break;
		
		if (bShowTitle && nReadNum>0)
		{
	//  	ShowLine("FRAME    ADDR    DATA    STATUS    PORT    SPARE ");
		  	ShowLine("FRAME    ADDR    DATA    STATUS    SPARE ");
		  	bShowTitle = FALSE;
		}
								
	    for (int i=0; i<nReadNum; i++)
	    {
	    	if(TestKey(VK_ESCAPE))
	    	{
	    		m_dwStartList = m_depth.endFrame;
	    		break;
	    	}
					    	
	    	DumpTraceBuf(szTmpShow, m_pTraceInfo+i);

        	ShowLine(szTmpShow); 
       	}	
     }      
	
	 if (bShowTitle){ // there is none frame showed yet.	
	 	ShowLine("No qualified frame!");
	 }
     
     if (m_pTraceInfo){
     	delete [] m_pTraceInfo;
     	m_pTraceInfo = NULL;
    }
	
//	RestoreLastTraceStatus();
}


int CCtlList::GetAbiFrame(DWORD& dwStart, DWORD dwEnd)
{
	int nErrorID;                
	
	if (dwStart > dwEnd) return -1;
		
	if (dwEnd-dwStart>MAX_LIST_LINE) dwEnd = dwStart+MAX_LIST_LINE-1;
	
	BYTE byFrameLen;
	BYTE byReadEnd;            

	ShowReadTraceCurSite(dwStart);    					
	nErrorID = emuListTraceBuff(dwStart, dwEnd, &m_tmpQualify, 
					&byFrameLen, m_pTraceInfo, &byReadEnd);
    
    if (nErrorID != ICE_OK) return -1;
    
//    if (byFrameLen>0) dwStart = m_pTraceInfo[byFrameLen-1].frameNo+1; 

    dwStart = dwEnd + 1;
    
    return byFrameLen;
}               

BOOL CCtlList::GetElapseTimeStr(char* szBuf)
{
	float fTime;
	
	int nStatus = emuGetTimerCount(fTime);
	
	if (nStatus != ICE_OK){
		szBuf[0] = '\0';
		return FALSE;   
	}

	int nTimePart;	
	
	// the unit of fTime is ns
	if (fTime > 1.0e9){
	// at least elapse time is greater than one second
	    if (fTime > 3.6e12){
	    // at least one hour
	    	nTimePart = (int)(fTime/3.6e12);
	    	wsprintf(szBuf, "%dhour ", nTimePart);
	    	fTime -= (float)(3.6e12 * nTimePart);
	    	szBuf += strlen(szBuf);
	    }
	    
	    if (fTime > 6e10){
	    // at least one minute
	    	nTimePart = (int)(fTime/6e10);
	    	wsprintf(szBuf, "%dmin ", nTimePart);
	    	fTime -= (float)(6e10 * nTimePart);
	    	szBuf += strlen(szBuf);
	    }
	    
//		nTimePart = (int)(fTime/1.0e9);
		sprintf(szBuf, "%5.2fs ", fTime/1.e9);
		szBuf += strlen(szBuf);
		
		return TRUE;
	}                              
	
	if (fTime > 1.0e6){
		nTimePart = (int)(fTime/1.0e6);
		wsprintf(szBuf, "%dms ", nTimePart);
		fTime -= (float)(nTimePart * 1.0e6);		
		szBuf += strlen(szBuf);
	}                              

	if (fTime > 1.0e3){
		nTimePart = (int)(fTime/1.0e3);
		wsprintf(szBuf, "%dus ", nTimePart);
		fTime -= (float)(nTimePart * 1.0e3);		
		szBuf += strlen(szBuf);
	}                              
	
	return TRUE;
}		
	

/**********************************end of file*******************************/

