#include "stdafx.h"

#include "trcserve.h"
#include "trcins.h"
#include "uicom2.h"

extern CTraceManage traceMan;


BOOL CTraceDqMem::ReadByte(BYTE& bByte)
{
	ASSERT(m_SiteFrom <= m_SiteCur );
	
	if (m_SiteCur > m_SiteTo)
	{
		m_nErrCode = ERR_FRAME_INVALID;
		return FALSE;
	}                         
	                      
	if(m_SiteCur.m_byIntSite==0) // if a word is read in trace, we need to impart it
	{
		if (!m_bInsStart && m_curAddr.m_dwAddr != m_lastAddr.m_dwAddr+1)
		{// address discontinous
			m_nErrCode = ERR_FRAME_ADDR_LEAP;
			return FALSE;
		}
	}                          

	bByte = traceMan.TraceCycleData(m_SiteCur);
	
	m_lastAddr = m_curAddr;                            

// update m_dwSiteCur, m_bInsStart and m_bFirstByte for next read	
	m_bInsStart = FALSE; // use class CDADTraceDq to set it to true
	                  
	SkipOneByte();	  
	
	return TRUE;                
}                 

void CTraceDqMem::SaveStatus()
{                     
	m_SaveSiteCur = m_SiteCur;
	m_bSaveInsStart = m_bInsStart;    
	m_SaveCurAddr = m_curAddr;
}

void CTraceDqMem::RestoreStatus()
{                                 
	m_SiteCur = m_SaveSiteCur;
	m_bInsStart = m_bSaveInsStart;
	m_curAddr = m_SaveCurAddr;
}

void CTraceDqMem::MarkInsStart()
{
	m_bInsStart = TRUE;
}

void CTraceDqMem::GetFrame(CFramePos& frame)
{
	memcpy(&frame, &m_SiteCur, sizeof(CFramePos));
}

void CTraceDqMem::SetFrameRange(CFramePos frameFrom, CFramePos frameTo)
{
	m_SiteFrom = frameFrom;
	m_SiteTo = frameTo;
}

BOOL CTraceDqMem::SkipOneByte()
{
	
	if (traceMan.IsTraceCycleByte(m_SiteCur.m_dwExtSite))
	{
		m_SiteCur.m_byIntSite = 0;
	}		
	else m_SiteCur.m_byIntSite = (m_SiteCur.m_byIntSite==0) ?
								 (BYTE)1 : (BYTE)0;
    
    if (m_SiteCur.m_byIntSite == 0)
    {
    	m_SiteCur.m_dwExtSite ++;
    	
    	return SetCurSite(m_SiteCur);
	}
	else m_curAddr.m_dwAddr++ ;
	
	return TRUE;
}   

BOOL CTraceDqMem::FlushBytes()
{   
	if (m_SiteCur > m_SiteTo) return FALSE;
	
	if (traceMan.IsTraceCycleByte(m_SiteCur.m_dwExtSite))
		return SkipOneByte();
	else{   
		if (m_SiteCur.m_byIntSite == 0)
			m_SiteCur.m_dwExtSite ++;
		else{
			m_SiteCur.m_dwExtSite += 2;
			m_SiteCur.m_byIntSite = 0; 
		}   
		       
		if (SetCurAddr())
			return FlushAsOddAddr();
		else return FALSE;
	}
}   

BOOL CTraceDqMem ::FlushBytesAsNeed(const ADDR& nextAddr)
{ // for branch instruction, flush may occur

	if (m_SiteCur > m_SiteTo) return FALSE;
	
	DWORD dwFrameNum = m_SiteCur.m_dwExtSite;

	if (traceMan.IsTraceCycleByte(m_SiteCur.m_dwExtSite))
		dwFrameNum ++;
	else{
		if (m_SiteCur.m_byIntSite == 0)
			dwFrameNum ++;
		else	
			dwFrameNum += 2;   
	}
	
	if (m_SiteTo < dwFrameNum) return FALSE;
		
	if ((traceMan.TraceCycleAddr(dwFrameNum) & 0xffff) == nextAddr.addr)
		return FlushBytes();
	else return TRUE;
}

BOOL CTraceDqMem::FlushAsOddAddr()
{
	if (m_SiteCur > m_SiteTo) return FALSE;
	
	if (!traceMan.IsTraceCycleByte(m_SiteCur.m_dwExtSite)
		&& m_SiteCur.m_byIntSite==0
		&& traceMan.TraceCycleAddr(m_SiteCur.m_dwExtSite)%2 != 0)
	{
		m_SiteCur.m_byIntSite = 1;
		return SetCurAddr();
	}                                     
	
	return TRUE;
}

BOOL CTraceDqMem::SkipInvalidFrame()
{       
	if (m_SiteCur.m_byIntSite != 0) return TRUE;

	BOOL bSkip = FALSE;
	
	for (; m_SiteCur<=m_SiteTo; m_SiteCur.m_dwExtSite++)
	{ // skip frame with R/W/AK status
		if (traceMan.TraceCycleStatus(m_SiteCur.m_dwExtSite)
			 != CTraceBase::STATUS_S)                  
		{
			bSkip = TRUE;
			continue;    
		}
		break;
	}
	
	if (bSkip){
	 	if (SetCurAddr())
			return FlushAsOddAddr();
	}
	
	return TRUE;
}

BOOL CTraceDqMem::SetCurSite(CFramePos newFrame)
{        
	BOOL bSkip = FALSE;
	
	m_SiteCur = newFrame;
	
	for (; m_SiteCur<=m_SiteTo; m_SiteCur.m_dwExtSite++)
	{ // skip frame with R/W/AK status
		if (traceMan.TraceCycleStatus(m_SiteCur.m_dwExtSite)
			 != CTraceBase::STATUS_S)                  
		{
			bSkip = TRUE;
			continue;    
		}
		break;
	}
    
	if (bSkip) m_SiteCur.m_byIntSite = 0;

 	if (SetCurAddr())
		return FlushAsOddAddr();
	
	return FALSE;
}	

BOOL CTraceDqMem::SetCurAddr()
{
	if (m_SiteCur > m_SiteTo) return FALSE;
	
	m_curAddr.m_dwAddr = traceMan.TraceCycleAddr(m_SiteCur.m_dwExtSite);
	
	if (m_curAddr.m_dwAddr % 2 == 0) // from even address
		m_curAddr.m_dwAddr += m_SiteCur.m_byIntSite;

	return TRUE;		
}
	
/*****************************************************************************
**
**	class CDADTraceDq
**
*****************************************************************************/


BOOL CDADTraceDq::DasTraceIns(CFramePos SiteFrom, CFramePos SiteEnd)
{
	m_listFrame.RemoveFreeAll();
	m_listAddr.RemoveFreeAll();
	m_listInstruction.RemoveAll();
	
	m_DADMem.SetFrameRange(SiteFrom, SiteEnd);
	m_DADMem.SetCurSite(SiteFrom);
	
	m_pDadOk = &m_dad196;

    ((C196DAD*)m_pDadOk)->SetCurWindow(::GetCurHWindow());
	

	WORD wInstrCounter = 0;	
	ADDR addrTmp;       
	
	CFramePos frameStart; // start frame number
		
	CDADAddr* pInsAddr;
	CInsFrame* pInsFrame = NULL;

	int nInsType = CAnalyseInstruction::TYPE_NORMAL;	
	while(1)                       
	{
		m_pDadOk->Baby.Clear();
		
		m_DADMem.SkipInvalidFrame();
		m_DADMem.GetAddr(addrTmp);
		m_DADMem.GetFrame(frameStart);
		
		m_DADMem.MarkInsStart();
			
		if (!m_pDadOk->Das(m_DADMem)){
			switch(m_pDadOk->GetDetailErrCode())
			{
				case CTraceDqMem::ERR_FRAME_INVALID:
					return TRUE;
				case CTraceDqMem::ERR_FRAME_ADDR_LEAP:
					nInsType = CAnalyseInstruction::TYPE_NORMAL;
					m_DADMem.FlushAsOddAddr();
					continue;
				default: 
					ASSERT(0);
					nInsType = CAnalyseInstruction::TYPE_NORMAL;
					continue;
			}                      
		}			

		wInstrCounter++; 
		
		nInsType = m_pDadOk->Baby.GetInstructionType();

		if (nInsType == CAnalyseInstruction::TYPE_JUMP)
			m_DADMem.FlushBytes();
		else if (nInsType == CAnalyseInstruction::TYPE_MAYBE_JUMP)
		{           
			ADDR addrNext;
			
			addrNext = ((CNextIceAddr*)((m_pDadOk->Baby).m_NextAddrSet)[0
					])->GetNextIceAddr();			
			m_DADMem.FlushBytesAsNeed(addrNext);
		}
								
		
		// record the information of the disassembled frame
		pInsFrame = new CInsFrame;
		pInsFrame->m_frameCur = frameStart;
		m_DADMem.GetFrame(pInsFrame->m_frameNext);
		m_listFrame.AddTail(pInsFrame);
		
		// record the start address of each instruction
		pInsAddr = new CDADAddr(addrTmp.addr);
		m_listAddr.AddTail(pInsAddr);
		
		m_listInstruction.AddTail(m_pDadOk->Baby.m_Instruction.GetStr());			
	}   
}                                                 


BOOL CDADTraceDq::TryInsBegin(CFramePos& InsStart, CFramePos SiteEnd)
{
	m_DADMem.SetFrameRange(InsStart, SiteEnd);
	m_DADMem.SetCurSite(InsStart);
	
	m_pDadOk = &m_dad196;

	int nInstrCounter = 0;		      
	int nTryCounter = 1;
	             
	m_DADMem.GetFrame(InsStart);

	int nInsType = CAnalyseInstruction::TYPE_NORMAL;
	
	for ( ; nInstrCounter<MAX_TRY_INS; )
	{
		m_pDadOk->Baby.Clear();

		m_DADMem.SkipInvalidFrame();
		m_DADMem.MarkInsStart();
			
		if (!m_pDadOk->Das(m_DADMem)){
			switch(m_pDadOk->GetDetailErrCode())
			{
				case CTraceDqMem::ERR_FRAME_INVALID:
					if (nInstrCounter > 0)
						return TRUE;
					else return FALSE;						
				case CTraceDqMem::ERR_FRAME_ADDR_LEAP:
					if (nInsType != CAnalyseInstruction::TYPE_NORMAL)
					{
						nInsType = CAnalyseInstruction::TYPE_NORMAL;
						m_DADMem.FlushAsOddAddr();
						continue;						            
					}
					// if last instruction is not jump instruction,
					// we handle it as below
				default:
					if (nTryCounter<MAX_TRY_TIMES)
					{
						nTryCounter++;
						nInstrCounter = 0;

						m_DADMem.SetCurSite(InsStart);
						if (!m_DADMem.SkipOneByte()) return FALSE;
						m_DADMem.GetFrame(InsStart);
                        
                        nInsType = CAnalyseInstruction::TYPE_NORMAL;
                        
						continue;
					}
					else return FALSE;						
			}                      
		}
		else if (m_pDadOk->Baby.m_isDirtyResult){
			if (nTryCounter<MAX_TRY_TIMES)
			{
				nTryCounter++;
				nInstrCounter = 0;

				m_DADMem.SetCurSite(InsStart);
				if (!m_DADMem.SkipOneByte()) return FALSE;
				m_DADMem.GetFrame(InsStart);
                
                nInsType = CAnalyseInstruction::TYPE_NORMAL;
                
				continue;
			}
			else return FALSE;						
		}
		
        nInsType = m_pDadOk->Baby.GetInstructionType();
        
        if (nInsType == CAnalyseInstruction::TYPE_JUMP)
        	m_DADMem.FlushBytes();
		else if (nInsType == CAnalyseInstruction::TYPE_MAYBE_JUMP)
		{           
			ADDR addrNext;
			
			addrNext = ((CNextIceAddr*)((m_pDadOk->Baby).m_NextAddrSet)[0
					])->GetNextIceAddr();			
			m_DADMem.FlushBytesAsNeed(addrNext);
		}
        	
		nInstrCounter++; 
	}	                                        
	
	return TRUE;
}       

void CDADTraceDq::DumpDadIns(DWORD& dwInsNum, IntroInsData* pInsData,
			CInsFrame* pInsFrame)
{
	dwInsNum = (DWORD)(m_listFrame.GetCount());
	
	if (dwInsNum==0) return;
	
	POSITION framePos = m_listFrame.GetHeadPosition();
	POSITION addrPos = m_listAddr.GetHeadPosition();
	POSITION resultPos = m_listInstruction.GetHeadPosition();

	for (DWORD i=0; i<dwInsNum; i++, pInsData++, pInsFrame++)
	{
		*pInsFrame = *((CInsFrame*)m_listFrame.GetNext(framePos));
		
		pInsData->dwAddr = ((CDADAddr*)m_listAddr.GetNext(
				addrPos))->m_dwAddr;
		pInsData->strIns = m_listInstruction.GetNext(resultPos);
	}
	
	m_listFrame.RemoveFreeAll();
	m_listAddr.RemoveFreeAll();
	m_listInstruction.RemoveAll();
}

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