
/***************************************************************************
**
**    Rev 1.0   07 Sep 1995 09:55:38   Shirley
** Initial revision.
**
****************************************************************************/

/////////////////////////////////////////////////////////////////////////////
//
//  File name: EMUGO.CPP
//
//  Description: The implementation file for the class: CEmulationGo.
//
//  Author: John Zhou
//
//  Date: 05/06/95
//
//  Modification:
//      1. 05/06/95, Initial version of the class: CEmulationGo.
//
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// Include files.
#include "stdafx.h"
#include "time.h"
//#include "resource.h"
                        
//#include "symbscty.h"                        
#include "uicom2.h"
#include "srcexp.h"
#include "emugo.h"
#include "abitype.h"
#include "emuhalt.h"
#include "trcpub.h"
#include "srcdef.h"

#include "ep196.h"
//added by john
//#include "abiextfn.h"
//#include "cpust.h"
//#include "errcodec.h"
//#include "mainfrm.h"

/////////////////////////////////////////////////////////////////////////////
// Debug flags.
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
                      

/////////////////////////////////////////////////////////////////////////////
// Type definitions.


/////////////////////////////////////////////////////////////////////////////
// Macro definitions.


/////////////////////////////////////////////////////////////////////////////
// Global variables.


/////////////////////////////////////////////////////////////////////////////
// Static variables.


/////////////////////////////////////////////////////////////////////////////
// External variables.

/////////////////////////////////////////////////////////////////////////////
// Global function prototypes.
//extern void ErrShow(U32 errorCode,BOOL bUI); //JOHN 96.3

int TestKey(WORD wKey)
{   
    MSG msg;
    if(PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
        PM_NOREMOVE|PM_NOYIELD)) {
        PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
            PM_REMOVE|PM_NOYIELD);
        if(msg.message == WM_KEYDOWN && msg.wParam == wKey) 
            return  1;        
    }            
    return  0;
}
BOOL EscapeAbort(void)
{
    // Test the key value.
    if ( 1 == ::TestKey(VK_ESCAPE)) {
        return (TRUE);
    }
    else {
        return (FALSE);
    }

}   // End of CMemoryBase::EscapeAbort().

void DelayOneSecond(void)
{
    // Assertion of the input parameters.
    
    // Get the current time.
    CTime t1 = CTime::GetCurrentTime();
    CTime t2;

    // Delay one second.
    do {
        t2 = CTime::GetCurrentTime();
    } while ( 0 == t2.GetSecond() - t1.GetSecond() );

}   // End of CSyntaxTest::DelayOneSecond().

unsigned long StrToVar(char* pszStr)
{
    // Assertion of the input parameters.
    ASSERT( pszStr );
    
    // Convertion.
    char* pszStopStr;
    unsigned long ul = strtoul(pszStr, &pszStopStr, 16);
    
    return (ul);

}   // End of CSyntaxLib::StrToVar().

/////////////////////////////////////////////////////////////////////////////
// Executable codes.

/////////////////////////////////////////////////////////////////////////////
// Public functions.

#ifdef __cplusplus
extern "C" {
#endif	// __cplusplus

/////////////////////////////////////////////////////////////////////////////
//
//  Name:   GoCmd().
//
//  Description: The main control routine of Go command.
//
//  Input:  nArgc - Number of input parameters.
//          pszArgv - Input parameters.
//
//  Output: None.
//
//  Return: None.
//
/////////////////////////////////////////////////////////////////////////////
void WINAPI GoCmd(int nArgc, char* pszArgv[])
{           
    // Assertion of the input parameters.
    ASSERT( nArgc >= 1 && nArgc <= 6 );
    for ( int i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }
    
    // Execute Go command.
    CEmulationGo* pEmulationGo = new CEmulationGo;
    if ( !pEmulationGo ) {                    
    	AfxMessageBox("Out of Memory!");
        ASSERT( FALSE );
        return;
    }
    else {  
        pEmulationGo->GoAction(nArgc, pszArgv);
        delete pEmulationGo;
    }
    
//    CEmulationGo objGo;
//    objGo.GoAction(nArgc, pszArgv);

}   // End of GoCmd().


// Emulation Go server.
void WINAPI EmuServerGo(int nMode, ADDR addr)
{
    // Assertion of the input parameters.
    // nMode:   1 - Go
    //          2 - Go From Addr
    //          3 - Go Till Addr
    //added by john 96.3
    //          4 - go fly
    //          5 - go fly from Addr
    //          6 - go fly till addr
    //ASSERT( 1 == nMode || 2 == nMode || 3 == nMode || 
    //        4 == nMode || 5 == nMode || 6 == nMode );
    
    // Go server for the Source window.
    CEmulationGo* pEmulationGo = new CEmulationGo;
    if ( !pEmulationGo ) {                         
    	AfxMessageBox("Out of Memory!");
        ASSERT( FALSE );
        return;
    }
    else {
        pEmulationGo->EmuServerGo(nMode,addr);
        delete pEmulationGo;
    }

}   // End of EmuServerGo().

#ifdef __cplusplus
}
#endif	// __cplusplus

/////////////////////////////////////////////////////////////////////////////
// Implementation codes of class: CEmulationGo.

// Construction.
CEmulationGo::CEmulationGo()
{
    // Assertion of the input parameters.
    

    m_nMonitorTimer = 0;
    m_bStartTimer = FALSE;
    m_uchFlyFlag = 0;
}   // End of CEmulationGo::CEmulationGo().


// Destruction.
CEmulationGo::~CEmulationGo()
{
    // Assertion of the input parameters.
    

}   // End of CEmulationGo::~CEmulationGo().


// Emulation Go command.
void CEmulationGo::GoAction(int nArgc, char* pszArgv[])
{
    // Assertion of the input parameters.
    //ASSERT( nArgc >= 1 && nArgc <= 5 );
    int i =0;
    for ( i = 0; i < nArgc; i++ ) {
        ASSERT( pszArgv[i] );
    }
    
    SetFlyFlag(0);
    //added 96.3 to support go fly anlysis
    char * ppTmpContain[20] ;
    ASSERT(nArgc<20);
    int j = 0;
    for (i = 0; i < nArgc; i++ ) 
        if ( 0 != stricmp(pszArgv[i], "FLY" )) {
            ppTmpContain[j++] = pszArgv[i];
        } else SetFlyFlag(1);   
    nArgc = j;    
    
    // Set the parameters.
    SetAddrUndefined(m_FromAddr);
    SetAddrUndefined(m_TillAddr);
    switch ( nArgc ) {
        case 1:
            // Go
            SetRunFlag(0);
            break;
        case 2:
            SetRunFlag(1);                  
            break;
        case 3:
            // Go [From adr1] | [Till adr2] | Monitor count
            SetRunFlag(0);
            if ( 0 == stricmp(ppTmpContain[1], "FROM") ) {
                SetAddrVar(ppTmpContain[2], m_FromAddr);
            }
            else if ( 0 == stricmp(ppTmpContain[1], "TILL") ) {
                SetAddrVar(ppTmpContain[2], m_TillAddr);
            }
            else {
                SetMonitorTimer(ppTmpContain[2]);
            }
            break;
        case 4:
            // Go Run [From adr1]
            SetRunFlag(1);
            SetAddrVar(ppTmpContain[3], m_FromAddr);
            break;
        case 5:
            // Go From adr1 Till adr2
            SetRunFlag(0);
            SetAddrVar(ppTmpContain[2], m_FromAddr);
            SetAddrVar(ppTmpContain[4], m_TillAddr);
            break;
        default:
            ASSERT( FALSE );
            break;
    }
    
    m_isServer = FALSE;
    // Call the Go kernel.
    GoKernel();                                        
    
    //delete ppTmpContain;

}   // End of CEmulationGo::GoAction().


// Set the Run flag.
void CEmulationGo::SetRunFlag(unsigned char uchRunFlag)
{
    // Assertion of the input parameters.
    ASSERT( 0 == uchRunFlag || 1 == uchRunFlag );
    
    // Set the Run flag.
    m_uchRunFlag = uchRunFlag;

}   // End of CEmulationGo::SetRunFlag().
// Set the Run flag.
void CEmulationGo::SetFlyFlag(unsigned char uchFlyFlag)
{
    // Assertion of the input parameters.
    ASSERT( 0 == uchFlyFlag || 1 == uchFlyFlag );
    
    // Set the Run flag.
    m_uchFlyFlag = uchFlyFlag;

}   // End of CEmulationGo::SetRunFlag().

// Go kernel routine.
void CEmulationGo::GoKernel(void)
{
    // Assertion of the input parameters.
    
    // Test parameters.
    //DumpVar(m_uchRunFlag);
    //DumpVar((unsigned long)m_FromAddr.m_uAddr);
    //DumpVar((unsigned long)m_TillAddr.m_uAddr);
    //added by john 96.3 
    if(GetCpuStatus2() == STATUS_GO) {   
        if ( !m_isServer ) SymShowLine("EP is running.");
        	else AfxMessageBox("EP is running.");
        return;                    
    }
    if(GetCpuStatus2() == STATUS_GORUN) {
    	if(0 == m_uchRunFlag && m_nMonitorTimer <= 0 &&
    	   MEM_UNDEFINED == m_FromAddr.addrType && MEM_UNDEFINED == m_TillAddr.addrType) {
    		CpuHalt();             
    		GoForGofly();
    		if ( !m_isServer ) ::ErrShow(ER_EMU_PROGRAM_IS_RUN,FALSE);
            return;
    	} else {
        	if ( !m_isServer ) ::ErrShow(ER_EMU_PROGRAM_IS_RUN,FALSE);
        		else ::ErrShow(ER_EMU_PROGRAM_IS_RUN,TRUE);
        	return;                    
        }
    }
    ASSERT(!(1 == m_uchRunFlag && 1 == m_uchFlyFlag));
    // Call the ABI function. 
    
    //marked by Chris, for Dome' fax, 3/26/97
    //another change is in mainfrm.cpp.
    //TraceWnd(1); //TRACE ON 
    //extern unsigned char traceStatus;
    //TraceWnd(traceStatus);
    
  
    ValidTraceBuffer();   
    TraceWnd(1);
    m_nErrorID = emuGo(m_uchRunFlag, m_FromAddr, m_TillAddr);
    if ( ICE_OK != m_nErrorID ) {                     
    	if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        	else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
        return;
    }
    else {                                               
        if ( !m_isServer ) ::SrcShowLine("Program is running.");
    }
    //added by john 96.3
    if (m_nMonitorTimer <= 0) {
        SetGoArg(m_TillAddr);
        // check run status john 96.3
        if ( 1 == m_uchRunFlag ) {
            SetCpuStatus2(STATUS_GORUN);
            if(!m_isServer)
            	SrcShowLine("Program is free running.");
            UpdateStatusBar(2, "Running");
    		UpdateStatusBarAll();
            return;
        } else {
            if ( 1 == m_uchFlyFlag) {
                SetCpuStatus2(STATUS_GOFLY);
                UpdateStatusBar(2, "Running");
    			UpdateStatusBarAll();
            } else {
            	SetCpuStatus2(STATUS_GO);        
            	UpdateStatusBar(2, "Running");
    			UpdateStatusBarAll();
            }	
        }    
    return;    
    }    
                
    
    // Test the EP status.
    AfxGetApp()->DoWaitCursor(1);           
    SetCpuStatus2(STATUS_GOMONI);
    
    UpdateStatusBar(2, "Running");
    UpdateStatusBarAll();
    
    do {
        // ESC to cancel Go command.
        if ( EscapeAbort() ) {
            m_nErrorID = emuAbort();
            if ( 0 != m_nErrorID ) {  
            	if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        			else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
            }
            else {
				if ( 0 == ::StkGetSourceAddr((ADDR&)(m_TillAddr)) ) {
				    // Call the ABI function.
				    m_uchRunFlag = 0;
				    m_FromAddr.addrType = MEM_UNDEFINED;
				    
    				TraceWnd(1); //TRACE ON 
    				m_nErrorID = emuGo(m_uchRunFlag,m_FromAddr,m_TillAddr);
				    if ( ICE_OK != m_nErrorID ) {
				        if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        					else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
				    }
				    else {
					    // Get CPU status.
					    DWORD uCpuStatus;
					    int nCount = 0;
					    do {
					    	emuGetCpuStatus(&uCpuStatus);
					    	nCount++;
					    } while (  0x10==(uCpuStatus & 0x10) && nCount < 10 );
				    }
                }
            }
            break;
        }
        
        // Start monitor timer.
        if ( m_nMonitorTimer > 0 && !m_bStartTimer ) {
            m_bStartTimer = TRUE;
            m_nTimerCount = 0;
        }
        
        // On monitor timer.
        if ( m_bStartTimer ) {
        	for(int i=0;i<m_nMonitorTimer;i++) {

        		DelayOneSecond();

		        // ESC to cancel Go command.
		        if ( EscapeAbort() ) {
		            m_nErrorID = emuAbort();
		            if ( 0 != m_nErrorID ) {
		            	if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        					else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
		            }
            		UpdateAllWindows();
            		
	            	if ( !m_isServer ) SrcShowLine("Abort by user.");
    					else AfxMessageBox("Abort by user.");
	                goto _Exit;
		        }
        	}
        	
            m_nErrorID = emuAbort();
            if ( 0 != m_nErrorID ) {                           
            	if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        			else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
                break;
            }
            
            UpdateAllWindows();
            
            m_bStartTimer = FALSE;
            
    		TraceWnd(1); //TRACE ON 
            m_nErrorID = emuGo(m_uchRunFlag, 
                               (ADDR&)m_FromAddr, (ADDR&)m_TillAddr);
            if ( 0 != m_nErrorID ) {
                if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        			else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
                break;
            }
        }

        // Detect if EP is stopped.
        /*
        if ( DetectEPStop() ) {
            if ( !MatchPatch() ) {
                ShowLine("Program is stopped.");
                break;
            }
            else {
                m_nErrorID =
                AbiGo(m_uchRunFlag, (ADDR&)m_FromAddr, (ADDR&)m_TillAddr);
                if ( ICE_OK != m_nErrorID ) {
                    DisplayErrorMessage();
                    break;
                }
            }
        } */
    } while ( TRUE );
    
_Exit:
    AfxGetApp()->DoWaitCursor(-1);
        
    SetCpuStatus2(STATUS_HALT);
    
    TraceWnd(0);     //TRACE OFF            
    UpdateStatusBar(2, "Halt");
    UpdateStatusBarAll();
}   // End of CEmulationGo::GoKernel().

void CEmulationGo::SetMonitorTimer(char* pszTimer)
{
    m_nMonitorTimer = StrToVar(pszTimer);
}

void CEmulationGo::SetAddrVar(char* Str,ADDR& addr)
{ 
	ADDRESS tmpAddr;
	ADDR_RETCODE nAddrRet = AdrTextToAddr(Str,tmpAddr);	
	addr.addrType = tmpAddr.adrSpace;
	addr.addr = tmpAddr.adrAddress;
	return ;
}

// Detect if EP is stopped.
BOOL CEmulationGo::DetectEPStop(void)
{
    // Assertion of the input parameters.

/*    
    // Set EV3 to detect.
    BUS_EVENT BusEvent;
    memset(&BusEvent, 0, sizeof(BUS_EVENT));
    BusEvent.qlfyType[0] = 3;
    BusEvent.qlfyType[9] = 1;
    BusEvent.extrn = 0;
    
    m_nErrorID = AbiSetEvent(BusEvent);
    if ( ICE_OK == m_nErrorID ) {
        return (TRUE);
    }
    else if ( ICE_EP_RUNNING == m_nErrorID ) {
        return (FALSE);
    }
    else {
        DisplayErrorMessage();
        return (TRUE);
    }
*/
    
    // Delay one second.
//    DelayOneSecond();
                            
    // Get CPU status.
    DWORD uCpuStatus;
    m_nErrorID = emuGetCpuStatus(&uCpuStatus);
    if ( ICE_OK != m_nErrorID ) {
        //DisplayErrorMessage();
        if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        	else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
        return (TRUE);
    }

    // Detect if EP is running.
    return ( 0x10 == (uCpuStatus & 0x010) ) ? FALSE : TRUE;

}   // End of CEmulationGo::DetectEPStop().



// Go server.
void CEmulationGo::EmuServerGo(int nMode, ADDR addr)
{
    // Assertion of the input parameters.
    //ASSERT( 1 == nMode || 2 == nMode || 3 == nMode );
    // nMode:   1 - Go
    //          2 - Go From Addr
    //          3 - Go Till Addr
    //added by john 96.3
    //          4 - go fly 
    //			5 - go fly from addr
    //			6 - go fly till addr
    //          7 - go run
    //          8 - go monitor
    // Dispatch the different mode.
    SetAddrUndefined(m_FromAddr);
    SetAddrUndefined(m_TillAddr);
    switch ( nMode ) {
        case 1:
            // Go
            SetRunFlag(0);
            break;
        case 2:
            // Go From Addr
            SetRunFlag(0);
            m_FromAddr.addr = addr.addr;
            m_FromAddr.addrType = addr.addrType;
            break;
        case 3:
            // Go Till Addr
            SetRunFlag(0);             
            m_TillAddr.addr = addr.addr;
            m_TillAddr.addrType = addr.addrType;
            break;                                       
        case 4:
            // Go fly
            SetFlyFlag(1);
            SetRunFlag(0);
            break;
        case 5:
            // Go fly From Addr
            SetFlyFlag(1);
            SetRunFlag(0);
            m_FromAddr.addr = addr.addr;
            m_FromAddr.addrType = addr.addrType;
            break;
        case 6:
            // Go fly Till Addr
            SetFlyFlag(1);
            SetRunFlag(0);
            m_TillAddr.addr = addr.addr;
            m_TillAddr.addrType = addr.addrType;
            break;    
        case 7:
            // Go run
            SetRunFlag(1);
            break;        
        case 8:
            // Go monitor time
            m_nMonitorTimer = (int)(addr.addr);
            break;
            
        default:
            ASSERT( FALSE );
            return;
            break;
    }
    
    // Call the Go kernel.
    m_isServer = TRUE;
    GoKernel();

}   // End of CEmulationGo::EmuServerGo().

// Update all the windows.
void CEmulationGo::UpdateAllWindows(void)
{
    // Assertion of the input parameters.

	// Added by Chen, 06/05/96.
	// Return if EP is not halt.
	unsigned char uchStatus;
	if ( FALSE == ::GetCpuStatus(uchStatus) ) {
		return;
	}
	else if ( STATUS_HALT != uchStatus && STATUS_GOMONI != uchStatus ) {
		return;
	}
	

    // Repaint all the windows.
    ::RepaintWindows();
    //::OnEmulation();
/*
    if ( ::isSourceOn ) {
        ::pSourceWnd->UpdateWindow();
    }
    if ( ::isVariableOn ) {
        ::pVariableWnd->UpdateWindow();
    }
    if ( ::isStackOn ) {
        ::pStackWnd->UpdateWindow();
    }
    if ( ::isCpuOn ) {
        ::pCpuWnd->UpdateWindow();
    }
    if ( ::isTraceOn ) {
        ::pTraceWnd->UpdateWindow();
    }
    if ( ::isPeriOn ) {
        ::pPeriWnd->UpdateWindow();
    }
    if ( ::isBMemOn ) {
        ::pBMemWnd->UpdateWindow();
    }
    for ( int i = 0; i <= 2; i++ ) {
        if ( ::isMemOn[i] ) {
            ::pMemWnd[i]->UpdateWindow();
        }
    }
*/    
} 
//ADDED BY JOHN 96.3 SUPPORT THE GO FLY FUNCTION
//NOW IT IS ONLY USED IN CHANGING GO STATUS FROM GORUN TO GO
BOOL CEmulationGo::GoForGofly()
{                   
    if(GetCpuStatus2() != STATUS_HALT )  return FALSE;
    SetRunFlag(0);
    SetAddrUndefined(m_FromAddr);
    GetGoArg(m_TillAddr);
    m_nErrorID = emuGo(m_uchRunFlag, m_FromAddr, m_TillAddr);
    if ( ICE_OK != m_nErrorID ) {
    	if ( !m_isServer ) ::ErrShow(ER_ICE_OK+m_nErrorID,FALSE);
        	else ::ErrShow(ER_ICE_OK+m_nErrorID,TRUE);
        //DisplayErrorMessage();
        return FALSE;
    }
    else {
        SetCpuStatus2(STATUS_GO);
        return TRUE;
    }
 
 return TRUE; 
 
 }

//ADDED BY JOHN 96.3
int TestKeyRemove(WORD wKey)
{   
    MSG msg;
    if(PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
        PM_REMOVE|PM_NOYIELD)) {
        PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST,
            PM_REMOVE|PM_NOYIELD);
        if(msg.message == WM_KEYDOWN && msg.wParam == wKey) 
            return  1;        
    }            
    return  0;
}

/**************************************************************************
**
** Name : WaitCmd()
**
** Function  is called by SHELL WINDOW TO do the wait cmd
**
**    Input  : 
**
**    Output : 
**    returN : 
** Notes:
**
**************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif	// __cplusplus
void WINAPI WaitCmd()
{         
	BYTE uchStatus;
    DWORD dwStatus;      
                                    
    if(STATUS_HALT == GetCpuStatus2()) return;
    SetCanTimer(FALSE);
    while (1) {
    	GetCpuStatus(uchStatus);
        uchStatus = GetCpuStatus2();
    	if(STATUS_HALT == uchStatus) break;
    	if(TestKeyRemove(VK_ESCAPE)) break;
    }	                            
    SetCanTimer(TRUE);
 }
#ifdef __cplusplus
}
#endif	// __cplusplus

/**************************************************************************
**
** Name : ContinueGo()
**
** Function  support go fly function
**
**    Input  : 
**
**    return : TRUE ==>  OK
**             FALSE ==> FAIL
** Notes:
**
**************************************************************************/
BOOL ContinueGo()       
{                                           
    CEmulationGo* pEmulationGo = new CEmulationGo;
    if ( !pEmulationGo ) {
        AfxMessageBox("Out of Memory!");
        ASSERT( FALSE );
        return FALSE;
    }
    else {  
        BOOL bResult = pEmulationGo->GoForGofly();
        delete pEmulationGo;
        return bResult;
    }
 
    return TRUE;
 }
//////////////////////////////// End of File ////////////////////////////////
