diff --git a/Makefile b/Makefile index 032e95b..063e5f4 100644 --- a/Makefile +++ b/Makefile @@ -499,6 +499,7 @@ ifeq ($(MMAP_JIT_CACHE), 1) CFLAGS += -DMMAP_JIT_CACHE endif +# Add -DTRACE_EVENTS to trace relevant events (IRQs, SMC, etc) # Add -DTRACE_INSTRUCTIONS to trace instruction execution # Can add -DTRACE_REGISTERS to additionally print register values ifeq ($(DEBUG), 1) diff --git a/cpu.c b/cpu.c index b662be6..e60b14b 100644 --- a/cpu.c +++ b/cpu.c @@ -23,6 +23,8 @@ #include "common.h" +#include "cpu_instrument.h" + u32 memory_region_access_read_u8[16]; u32 memory_region_access_read_s8[16]; u32 memory_region_access_read_u16[16]; @@ -57,108 +59,6 @@ const u8 bit_count[256] = }; -#ifdef REGISTER_USAGE_ANALYZE - -u64 instructions_total = 0; - -u64 arm_reg_freq[16]; -u64 arm_reg_access_total = 0; -u64 arm_instructions_total = 0; - -u64 thumb_reg_freq[16]; -u64 thumb_reg_access_total = 0; -u64 thumb_instructions_total = 0; - -// mla/long mla's addition operand are not counted yet. - -#define using_register(instruction_set, register, type) \ - instruction_set##_reg_freq[register]++; \ - instruction_set##_reg_access_total++ \ - -#define using_register_list(instruction_set, rlist, count) \ -{ \ - u32 i; \ - for(i = 0; i < count; i++) \ - { \ - if((reg_list >> i) & 0x01) \ - { \ - using_register(instruction_set, i, memory_target); \ - } \ - } \ -} \ - -#define using_instruction(instruction_set) \ - instruction_set##_instructions_total++; \ - instructions_total++ \ - -int sort_tagged_element(const void *_a, const void *_b) -{ - const u64 *a = _a; - const u64 *b = _b; - - return (int)(b[1] - a[1]); -} - -void print_register_usage(void) -{ - u32 i; - u64 arm_reg_freq_tagged[32]; - u64 thumb_reg_freq_tagged[32]; - double percent; - double percent_total = 0.0; - - for(i = 0; i < 16; i++) - { - arm_reg_freq_tagged[i * 2] = i; - arm_reg_freq_tagged[(i * 2) + 1] = arm_reg_freq[i]; - thumb_reg_freq_tagged[i * 2] = i; - thumb_reg_freq_tagged[(i * 2) + 1] = thumb_reg_freq[i]; - } - - qsort(arm_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element); - qsort(thumb_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element); - - printf("ARM register usage (%lf%% ARM instructions):\n", - (arm_instructions_total * 100.0) / instructions_total); - for(i = 0; i < 16; i++) - { - percent = (arm_reg_freq_tagged[(i * 2) + 1] * 100.0) / - arm_reg_access_total; - percent_total += percent; - printf("r%02d: %lf%% (-- %lf%%)\n", - (u32)arm_reg_freq_tagged[(i * 2)], percent, percent_total); - } - - percent_total = 0.0; - - printf("\nThumb register usage (%lf%% Thumb instructions):\n", - (thumb_instructions_total * 100.0) / instructions_total); - for(i = 0; i < 16; i++) - { - percent = (thumb_reg_freq_tagged[(i * 2) + 1] * 100.0) / - thumb_reg_access_total; - percent_total += percent; - printf("r%02d: %lf%% (-- %lf%%)\n", - (u32)thumb_reg_freq_tagged[(i * 2)], percent, percent_total); - } - - memset(arm_reg_freq, 0, sizeof(u64) * 16); - memset(thumb_reg_freq, 0, sizeof(u64) * 16); - arm_reg_access_total = 0; - thumb_reg_access_total = 0; -} - -#else - -#define using_register(instruction_set, register, type) \ - -#define using_register_list(instruction_set, rlist, count) \ - -#define using_instruction(instruction_set) \ - -#endif - - #define arm_decode_data_proc_reg(opcode) \ u32 rn = (opcode >> 16) & 0x0F; \ u32 rd = (opcode >> 12) & 0x0F; \ @@ -1785,6 +1685,10 @@ arm_loop: break; } + #ifdef TRACE_INSTRUCTIONS + interp_trace_instruction(pc, 1); + #endif + switch((opcode >> 20) & 0xFF) { case 0x00: @@ -3274,6 +3178,10 @@ thumb_loop: pc &= ~0x01; opcode = readaddress16(pc_address_block, (pc & 0x7FFF)); + #ifdef TRACE_INSTRUCTIONS + interp_trace_instruction(pc, 0); + #endif + switch((opcode >> 8) & 0xFF) { case 0x00 ... 0x07: diff --git a/cpu_instrument.h b/cpu_instrument.h new file mode 100644 index 0000000..f7bc673 --- /dev/null +++ b/cpu_instrument.h @@ -0,0 +1,117 @@ + +// Instrumentation and debugging code +// Used to count instruction and register usage +// Also provides some tracing capabilities + + +#ifdef REGISTER_USAGE_ANALYZE + + u64 instructions_total = 0; + u64 arm_reg_freq[16]; + u64 arm_reg_access_total = 0; + u64 arm_instructions_total = 0; + u64 thumb_reg_freq[16]; + u64 thumb_reg_access_total = 0; + u64 thumb_instructions_total = 0; + + // mla/long mla's addition operand are not counted yet. + + #define using_register(instruction_set, register, type) \ + instruction_set##_reg_freq[register]++; \ + instruction_set##_reg_access_total++ \ + + #define using_register_list(instruction_set, rlist, count) \ + { \ + u32 i; \ + for(i = 0; i < count; i++) \ + { \ + if((reg_list >> i) & 0x01) \ + { \ + using_register(instruction_set, i, memory_target); \ + } \ + } \ + } \ + + #define using_instruction(instruction_set) \ + instruction_set##_instructions_total++; \ + instructions_total++ \ + + int sort_tagged_element(const void *_a, const void *_b) + { + const u64 *a = _a; + const u64 *b = _b; + + return (int)(b[1] - a[1]); + } + + void print_register_usage(void) + { + u32 i; + u64 arm_reg_freq_tagged[32]; + u64 thumb_reg_freq_tagged[32]; + double percent; + double percent_total = 0.0; + + for(i = 0; i < 16; i++) + { + arm_reg_freq_tagged[i * 2] = i; + arm_reg_freq_tagged[(i * 2) + 1] = arm_reg_freq[i]; + thumb_reg_freq_tagged[i * 2] = i; + thumb_reg_freq_tagged[(i * 2) + 1] = thumb_reg_freq[i]; + } + + qsort(arm_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element); + qsort(thumb_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element); + + printf("ARM register usage (%lf%% ARM instructions):\n", + (arm_instructions_total * 100.0) / instructions_total); + for(i = 0; i < 16; i++) + { + percent = (arm_reg_freq_tagged[(i * 2) + 1] * 100.0) / + arm_reg_access_total; + percent_total += percent; + printf("r%02d: %lf%% (-- %lf%%)\n", + (u32)arm_reg_freq_tagged[(i * 2)], percent, percent_total); + } + + percent_total = 0.0; + + printf("\nThumb register usage (%lf%% Thumb instructions):\n", + (thumb_instructions_total * 100.0) / instructions_total); + for(i = 0; i < 16; i++) + { + percent = (thumb_reg_freq_tagged[(i * 2) + 1] * 100.0) / + thumb_reg_access_total; + percent_total += percent; + printf("r%02d: %lf%% (-- %lf%%)\n", + (u32)thumb_reg_freq_tagged[(i * 2)], percent, percent_total); + } + + memset(arm_reg_freq, 0, sizeof(u64) * 16); + memset(thumb_reg_freq, 0, sizeof(u64) * 16); + arm_reg_access_total = 0; + thumb_reg_access_total = 0; + } + +#else /* REGISTER_USAGE_ANALYZE */ + + #define using_register(instruction_set, register, type) + #define using_register_list(instruction_set, rlist, count) + #define using_instruction(instruction_set) + +#endif /* REGISTER_USAGE_ANALYZE */ + + +#ifdef TRACE_INSTRUCTIONS + static void interp_trace_instruction(u32 pc, u32 mode) + { + if (mode) + printf("Executed arm %x\n", pc); + else + printf("Executed thumb %x\n", pc); + #ifdef TRACE_REGISTERS + print_regs(); + #endif + } +#endif + diff --git a/main.c b/main.c index b97eecf..8da907f 100644 --- a/main.c +++ b/main.c @@ -111,6 +111,8 @@ u32 function_cc update_gba(int remaining_cycles) { irq_type irq_raised = IRQ_NONE; int dma_cycles; + trace_update_gba(remaining_cycles); + remaining_cycles = MAX(remaining_cycles, -64); do diff --git a/main.h b/main.h index 43457a5..21a56f2 100644 --- a/main.h +++ b/main.h @@ -93,6 +93,13 @@ extern boot_mode selected_boot_mode; void print_regs(void); #endif +#ifdef TRACE_EVENTS + #define trace_update_gba(remcyc) \ + printf("update_gba: %d remaining cycles\n", (remcyc)); +#else /* TRACE_EVENTS */ + #define trace_update_gba(x) +#endif + #endif