@@ -14,17 +14,19 @@ | |||||
do { \ | do { \ | ||||
if (logging_level_ >= level) { \ | if (logging_level_ >= level) { \ | ||||
fprintf(dest, type " " __VA_ARGS__); \ | fprintf(dest, type " " __VA_ARGS__); \ | ||||
extra; \ | |||||
extra \ | |||||
fprintf(dest, "\n"); \ | fprintf(dest, "\n"); \ | ||||
after; \ | |||||
after \ | |||||
} \ | } \ | ||||
} while (0); | } while (0); | ||||
#define LOG_ERR_(...) LOG_MSG_(stderr, __VA_ARGS__) | #define LOG_ERR_(...) LOG_MSG_(stderr, __VA_ARGS__) | ||||
#define LOG_OUT_(...) LOG_MSG_(stdout, __VA_ARGS__) | #define LOG_OUT_(...) LOG_MSG_(stdout, __VA_ARGS__) | ||||
#define PRINT_ERR_ fprintf(stderr, ": %s", strerror(errno)) | |||||
#define EXIT_FAIL_ exit(EXIT_FAILURE) | |||||
#define PRINT_ERR_ fprintf(stderr, ": %s", strerror(errno)); | |||||
#define EXIT_FAIL_ exit(EXIT_FAILURE); | |||||
#define NO_EOL_ if (0) | |||||
#define FLUSH_OUT_ fflush(stdout); | |||||
#define FATAL_TEXT_ "\x1b[1m\x1b[31m" "fatal:" "\x1b[0m" | #define FATAL_TEXT_ "\x1b[1m\x1b[31m" "fatal:" "\x1b[0m" | ||||
#define ERROR_TEXT_ "\x1b[1m\x1b[31m" "error:" "\x1b[0m" | #define ERROR_TEXT_ "\x1b[1m\x1b[31m" "error:" "\x1b[0m" | ||||
@@ -44,6 +46,7 @@ unsigned logging_level_; | |||||
#define WARN_ERRNO(...) LOG_ERR_(0, WARN_TEXT_, PRINT_ERR_, {}, __VA_ARGS__) | #define WARN_ERRNO(...) LOG_ERR_(0, WARN_TEXT_, PRINT_ERR_, {}, __VA_ARGS__) | ||||
#define DEBUG(...) LOG_OUT_(1, DEBUG_TEXT_, {}, {}, __VA_ARGS__) | #define DEBUG(...) LOG_OUT_(1, DEBUG_TEXT_, {}, {}, __VA_ARGS__) | ||||
#define TRACE(...) LOG_OUT_(2, TRACE_TEXT_, {}, {}, __VA_ARGS__) | #define TRACE(...) LOG_OUT_(2, TRACE_TEXT_, {}, {}, __VA_ARGS__) | ||||
#define TRACE_NOEOL(...) LOG_OUT_(2, TRACE_TEXT_, NO_EOL_, FLUSH_OUT_, __VA_ARGS__) | |||||
#define SET_LOG_LEVEL(level) logging_level_ = (level); | #define SET_LOG_LEVEL(level) logging_level_ = (level); | ||||
#define DEBUG_LEVEL (logging_level_ >= 1) | #define DEBUG_LEVEL (logging_level_ >= 1) | ||||
@@ -82,6 +82,10 @@ void z80_power(Z80 *z80) | |||||
z80->except = false; | z80->except = false; | ||||
z80->pending_cycles = 0; | z80->pending_cycles = 0; | ||||
z80->trace.fresh = true; | |||||
z80->trace.last_addr = 0; | |||||
z80->trace.counter = 0; | |||||
} | } | ||||
/* | /* | ||||
@@ -182,8 +186,19 @@ static inline void increment_refresh_counter(Z80 *z80) | |||||
@TRACE_LEVEL | @TRACE_LEVEL | ||||
Trace the instruction about to be executed by the CPU. | Trace the instruction about to be executed by the CPU. | ||||
*/ | */ | ||||
static inline void trace_instruction(const Z80 *z80) | |||||
static inline void trace_instruction(Z80 *z80) | |||||
{ | { | ||||
if (z80->regfile.pc == z80->trace.last_addr && !z80->trace.fresh) { | |||||
z80->trace.counter++; | |||||
if (!(z80->trace.counter % (1 << 14))) | |||||
TRACE_NOEOL("repeat last: %llu times\r", z80->trace.counter); | |||||
return; | |||||
} | |||||
if (z80->trace.fresh) | |||||
z80->trace.fresh = false; | |||||
z80->trace.last_addr = z80->regfile.pc; | |||||
z80->trace.counter = 0; | |||||
uint32_t quad = mmu_read_quad(z80->mmu, z80->regfile.pc); | uint32_t quad = mmu_read_quad(z80->mmu, z80->regfile.pc); | ||||
uint8_t bytes[4] = {quad, quad >> 8, quad >> 16, quad >> 24}; | uint8_t bytes[4] = {quad, quad >> 8, quad >> 16, quad >> 24}; | ||||
DisasInstr *instr = disassemble_instruction(bytes); | DisasInstr *instr = disassemble_instruction(bytes); | ||||
@@ -23,11 +23,18 @@ typedef struct { | |||||
} Z80RegFile; | } Z80RegFile; | ||||
typedef struct { | typedef struct { | ||||
bool fresh; | |||||
uint16_t last_addr; | |||||
uint64_t counter; | |||||
} Z80TraceInfo; | |||||
typedef struct { | |||||
Z80RegFile regfile; | Z80RegFile regfile; | ||||
MMU *mmu; | MMU *mmu; | ||||
bool except; | bool except; | ||||
uint8_t exc_code, exc_data; | uint8_t exc_code, exc_data; | ||||
double pending_cycles; | double pending_cycles; | ||||
Z80TraceInfo trace; | |||||
} Z80; | } Z80; | ||||
/* Functions */ | /* Functions */ | ||||