/* Copyright (C) 2008 Guillaume Duhamel
Copyright (C) 2009-2010 DeSmuME team
This file is part of DeSmuME
DeSmuME 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 2 of the License, or
(at your option) any later version.
DeSmuME 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 DeSmuME; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DEBUG_H
#define DEBUG_H
#include <vector>
#include <iostream>
#include <bitset>
#include <cstdarg>
#include "types.h"
#include "mem.h"
#include "emufile.h"
struct DebugStatistics
{
DebugStatistics();
struct InstructionHits {
InstructionHits();
uint32_t thumb[1024];
uint32_t arm[4096];
} instructionHits[2]; //one for each cpu
int32_t sequencerExecutionCounters[32];
void print();
void printSequencerExecutionCounters();
};
extern DebugStatistics DEBUG_statistics;
void DEBUG_reset();
void DEBUG_dumpMemory(EMUFILE* fp);
struct armcpu_t;
class Logger {
protected:
void (*callback)(const Logger& logger, const char * format);
std::ostream * out;
unsigned int flags;
static std::vector<Logger *> channels;
static void fixSize(unsigned int channel);
public:
Logger();
~Logger();
void vprintf(const char * format, va_list l, const char * filename, unsigned int line);
void setOutput(std::ostream * o);
void setCallback(void (*cback)(const Logger& logger, const char * message));
void setFlag(unsigned int flag);
std::ostream& getOutput() const;
static const int LINE = 1;
static const int FILE = 2;
static void log(unsigned int channel, const char * file, unsigned int line, const char * format, ...);
static void log(unsigned int channel, const char * file, unsigned int line, std::ostream& os);
static void log(unsigned int channel, const char * file, unsigned int line, unsigned int flag);
static void log(unsigned int channel, const char * file, unsigned int line, void (*callback)(const Logger& logger, const char * message));
};
#if defined(DEBUG) || defined(GPUDEBUG) || defined(DIVDEBUG) || defined(SQRTDEBUG) || defined(DMADEBUG) || defined(DEVELOPER)
#define LOGC(channel, ...) Logger::log(channel, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LOGC(...) {}
#endif
#ifdef DEBUG
#define LOG(...) LOGC(0, __VA_ARGS__)
#else
#define LOG(...) {}
#endif
#ifdef GPUDEBUG
#define GPULOG(...) LOGC(1, __VA_ARGS__)
#else
#define GPULOG(...) {}
#endif
#ifdef DIVDEBUG
#define DIVLOG(...) LOGC(2, __VA_ARGS__)
#else
#define DIVLOG(...) {}
#endif
#ifdef SQRTDEBUG
#define SQRTLOG(...) LOGC(3, __VA_ARGS__)
#else
#define SQRTLOG(...) {}
#endif
#ifdef DMADEBUG
#define DMALOG(...) LOGC(4, __VA_ARGS__)
#else
#define DMALOG(...) {}
#endif
#ifdef CFLASHDEBUG
#define CFLASHLOG(...) LOGC(5, __VA_ARGS__)
#else
#define CFLASHLOG(...) {}
#endif
#ifdef UNTESTEDOPCODEDEBUG
#define UNTESTEDOPCODELOG(...) LOGC(6, __VA_ARGS__)
#else
#define UNTESTEDOPCODELOG(...) {}
#endif
#ifdef DEVELOPER
#define PROGINFO(...) LOGC(7, __VA_ARGS__)
#else
#define PROGINFO(...) {}
#endif
#define INFOC(channel, ...) Logger::log(channel, __FILE__, __LINE__, __VA_ARGS__)
#define INFO(...) INFOC(10, __VA_ARGS__)
void IdeasLog(armcpu_t* cpu);
void NocashMessage(armcpu_t* cpu);
enum EDEBUG_EVENT
{
DEBUG_EVENT_READ=1, //read from arm9 or arm7 bus, including cpu prefetch
DEBUG_EVENT_WRITE=2, //write on arm9 or arm7 bus
DEBUG_EVENT_EXECUTE=4, //prefetch on arm9 or arm7, triggered after the read event
DEBUG_EVENT_ACL_EXCEPTION=8, //acl exception on arm9
};
enum EDEBUG_NOTIFY
{
DEBUG_NOTIFY_READ_BEYOND_END_OF_CART,
DEBUG_NOTIFY_MAX
};
class DebugNotify
{
public:
void NextFrame();
void ReadBeyondEndOfCart(uint32_t addr, uint32_t romsize);
private:
std::bitset<DEBUG_NOTIFY_MAX> pingBits;
std::bitset<DEBUG_NOTIFY_MAX> enableBits;
bool ping(EDEBUG_NOTIFY which);
};
extern DebugNotify DEBUG_Notify;
struct armcpu_t;
//information about a debug event will be stuffed into here by the generator
struct TDebugEventData
{
MMU_ACCESS_TYPE memAccessType;
uint32_t procnum, addr, size, val;
armcpu_t* cpu();
};
extern TDebugEventData DebugEventData;
//bits in here are set according to what debug handlers are installed?
//for now it is just a single bit
extern uint32_t debugFlag;
inline bool CheckDebugEvent(EDEBUG_EVENT)
{
//for now, debug events are only handled in dev+ builds
#ifndef DEVELOPER
return false;
#else
if(!debugFlag) return false;
return true;
#endif
}
void HandleDebugEvent_Read();
void HandleDebugEvent_Write();
void HandleDebugEvent_Execute();
void HandleDebugEvent_ACL_Exception();
inline void HandleDebugEvent(EDEBUG_EVENT event)
{
switch(event)
{
case DEBUG_EVENT_READ: HandleDebugEvent_Read(); return;
case DEBUG_EVENT_WRITE: HandleDebugEvent_Write(); return;
case DEBUG_EVENT_EXECUTE: HandleDebugEvent_Execute(); return;
case DEBUG_EVENT_ACL_EXCEPTION: HandleDebugEvent_ACL_Exception(); return;
}
}
#endif