/* 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 #include #include #include #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 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 pingBits; std::bitset 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