/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see .
**/
/*
* Watch.cpp
*/
#ifdef SUPERMODEL_DEBUGGER
#include "CPUDebug.h"
#include "Debugger.h"
#include "IO.h"
#include "Watch.h"
#include
using namespace std;
namespace Debugger
{
UINT32 CWatch::GetIOAddress(CIO *io)
{
CMappedIO *mappedIO = dynamic_cast(io);
return (mappedIO != NULL ? mappedIO->addr : 0);
}
CWatch::CWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, char wSymbol, const char *wType, bool wTrigRead, bool wTrigWrite) :
CAddressRef(wCPU, wAddr, wSize), io(NULL), symbol(wSymbol), type(wType), trigRead(wTrigRead), trigWrite(wTrigWrite), active(true),
readCount(0), writeCount(0)
{
//
}
CWatch::CWatch(CCPUDebug *wCPU, CIO *wIO, char wSymbol, const char *wType, bool wTrigInput, bool mTrigOutput) :
CAddressRef(wCPU, GetIOAddress(wIO), wIO->dataSize), io(wIO), symbol(wSymbol), type(wType), trigRead(wTrigInput), trigWrite(mTrigOutput), active(true),
readCount(0), writeCount(0)
{
//
}
bool CWatch::HasValue()
{
if (io != NULL)
return io->inCount + io->outCount > 0;
else
return true;
}
UINT64 CWatch::GetValue()
{
if (io != NULL)
return *io->last;
else
return cpu->ReadMem(addr, size);
}
bool CWatch::CheckRead(UINT32 cAddr, unsigned cDataSize, UINT64 data)
{
if (!active || !trigRead)
return false;
// Take care with read that was not aligned with watch address and size
UINT64 sData = CDebugger::GetSlottedData(cAddr, cDataSize, data, addr, size);
return CheckBreak(true, sData);
}
bool CWatch::CheckWrite(UINT32 cAddr, unsigned cDataSize, UINT64 data)
{
if (!active || !trigWrite)
return false;
// Take care with write that was not aligned with watch address and size
UINT64 sData = CDebugger::GetSlottedData(cAddr, cDataSize, data, addr, size);
return CheckBreak(false, sData);
}
bool CWatch::CheckInput(CIO *cIO, UINT64 data)
{
// No need to align data as already aligned by CIO
return active && trigRead && CheckBreak(true, data);
}
bool CWatch::CheckOutput(CIO *cIO, UINT64 data)
{
// No need to align data as already aligned by CIO
return active && trigWrite && CheckBreak(false, data);
}
void CWatch::Reset()
{
//
}
bool CWatch::GetInfo(char *str)
{
return false;
}
CSimpleWatch::CSimpleWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite) :
CWatch(wCPU, wAddr, wSize, '*', "simple", wTrigRead, wTrigWrite)
{
//
}
CSimpleWatch::CSimpleWatch(CCPUDebug *wCPU, CIO *wIO, bool wTrigInput, bool mTrigOutput) :
CWatch(wCPU, wIO, '*', "simple", wTrigInput, mTrigOutput)
{
//
}
bool CSimpleWatch::CheckBreak(bool isRead, UINT64 data)
{
return true;
}
CCountWatch::CCountWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite, unsigned count) :
CWatch(wCPU, wAddr, wSize, '+', "count", wTrigRead, wTrigWrite), m_count(count), m_counter(0)
{
//
}
CCountWatch::CCountWatch(CCPUDebug *wCPU, CIO *wIO, bool wTrigInput, bool mTrigOutput, unsigned count) :
CWatch(wCPU, wIO, '+', "count", wTrigInput, mTrigOutput), m_count(count), m_counter(0)
{
//
}
bool CCountWatch::CheckBreak(bool isRead, UINT64 data)
{
return ++m_counter == m_count;
}
void CCountWatch::Reset()
{
m_counter = 0;
}
bool CCountWatch::GetInfo(char *str)
{
sprintf(str, "%d / %d", m_counter, m_count);
return true;
}
CMatchWatch::CMatchWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite, vector &dataSeq) :
CWatch(wCPU, wAddr, wSize, 'M', "match", wTrigRead, wTrigWrite), m_dataLen(dataSeq.size()), m_counter(0)
{
m_dataArray = new UINT64[m_dataLen];
copy(dataSeq.begin(), dataSeq.end(), m_dataArray);
}
CMatchWatch::CMatchWatch(CCPUDebug *wCPU, CIO *wIO, bool wTrigInput, bool mTrigOutput, vector &dataSeq) :
CWatch(wCPU, wIO, 'M', "match", wTrigInput, mTrigOutput), m_dataLen(dataSeq.size()), m_counter(0)
{
m_dataArray = new UINT64[m_dataLen];
copy(dataSeq.begin(), dataSeq.end(), m_dataArray);
}
CMatchWatch::~CMatchWatch()
{
delete m_dataArray;
}
bool CMatchWatch::CheckBreak(bool isRead, UINT64 data)
{
if (m_dataArray[m_counter] == data)
m_counter++;
else
m_counter = 0;
return m_counter == m_dataLen;
}
void CMatchWatch::Reset()
{
m_counter = 0;
}
bool CMatchWatch::GetInfo(char *str)
{
sprintf(str, "%d / %d matched", m_counter, m_dataLen);
return true;
}
CCaptureWatch::CCaptureWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite, unsigned wMaxLen) :
CWatch(wCPU, wAddr, wSize, 'C', "capture", wTrigRead, wTrigWrite), m_maxLen(min(255, wMaxLen)), m_len(0), m_index(0)
{
//
}
CCaptureWatch::CCaptureWatch(CCPUDebug *wCPU, CIO *wIO, bool wTrigInput, bool mTrigOutput, unsigned wMaxLen) :
CWatch(wCPU, wIO, 'C', "capture", wTrigInput, mTrigOutput), m_maxLen(min(255, wMaxLen)), m_len(0), m_index(0)
{
//
}
bool CCaptureWatch::CheckBreak(bool isRead, UINT64 data)
{
if (m_len < m_maxLen)
{
m_dataVals[m_len] = data;
m_dataRW[m_len] = isRead;
m_len++;
m_index = 0;
}
else
{
m_dataVals[m_index] = data;
m_dataRW[m_index] = isRead;
m_index++;
if (m_index >= m_maxLen)
m_index = 0;
}
return false;
}
void CCaptureWatch::Reset()
{
m_len = 0;
m_index = 0;
}
bool CCaptureWatch::GetInfo(char *str)
{
char dataStr[25];
unsigned ind, len;
str[0] = '\0';
if (m_len == 0)
return true;
else if (m_len < m_maxLen)
{
ind = m_len - 1;
len = m_len;
}
else
{
if (m_index == 0)
ind = m_maxLen - 1;
else
ind = m_index - 1;
len = m_maxLen;
}
for (unsigned i = 0; i < len; i++)
{
UINT64 data = m_dataVals[ind];
bool isRead = m_dataRW[ind];
cpu->FormatData(dataStr, size, data);
if (i > 0)
strcat(str, " ");
strcat(str, (isRead ? "<" : ">"));
strcat(str, dataStr);
if (ind == 0)
ind = m_maxLen - 1;
else
ind--;
}
return true;
}
CPrintWatch::CPrintWatch(CCPUDebug *wCPU, UINT32 wAddr, unsigned wSize, bool wTrigRead, bool wTrigWrite) :
CWatch(wCPU, wAddr, wSize, 'P', "print", wTrigRead, wTrigWrite)
{
//
}
CPrintWatch::CPrintWatch(CCPUDebug *wCPU, CIO *io, bool wTrigInput, bool mTrigOutput) :
CWatch(wCPU, io, 'P', "print", wTrigInput, mTrigOutput)
{
//
}
bool CPrintWatch::CheckBreak(bool isRead, UINT64 data)
{
const char *sizeStr = CDebugger::GetSizeString(size);
const char *rwStr = (isRead ? "Read" : "Wrote");
const char *tfStr = (isRead ? "from" : "to");
char dataStr[50];
char addrStr[50];
char locStr[50];
cpu->FormatData(dataStr, size, data);
cpu->FormatAddress(addrStr, addr, true);
if (io != NULL)
{
io->GetLocation(locStr);
cpu->debugger->PrintEvent(cpu, "%s %s data (%s) %s I/O %s.\n", rwStr, sizeStr, dataStr, tfStr, locStr);
}
else
cpu->debugger->PrintEvent(cpu, "%s %s data (%s) %s memory %s.\n", rwStr, sizeStr, dataStr, tfStr, addrStr);
return false;
}
}
#endif // SUPERMODEL_DEBUGGER