From f9ff1cf2e19b1c64128546f3fd5597489e6523bb Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Fri, 8 Feb 2019 09:35:14 +0100 Subject: [PATCH 1/5] setup hook interface for debugging --- include/syn68k_public.h | 7 +++++++ runtime/init.c | 1 + 2 files changed, 8 insertions(+) diff --git a/include/syn68k_public.h b/include/syn68k_public.h index 1cb8698..ff36728 100644 --- a/include/syn68k_public.h +++ b/include/syn68k_public.h @@ -196,6 +196,13 @@ extern uint16 callback_dummy_address_space[]; #define MAGIC_EXIT_EMULATOR_ADDRESS (MAGIC_ADDRESS_BASE + 0) #define MAGIC_RTE_ADDRESS (MAGIC_ADDRESS_BASE + 2) +typedef struct { + uint32_t (*debugger)(uint32_t addr); + uint32_t (*getNextBreakpoint)(uint32_t addr); +} DebuggerCallbacks; + +extern DebuggerCallbacks syn68k_debugger_callbacks; + /* Address bits that have meaning, for the CLEAN() macro, below. */ #define LEGAL_ADDRESS_BITS 0xFFFFFFFFUL diff --git a/runtime/init.c b/runtime/init.c index 72f05d7..837244f 100644 --- a/runtime/init.c +++ b/runtime/init.c @@ -24,6 +24,7 @@ uint32 ROMlib_offset; uint64 ROMlib_offsets[OFFSET_TABLE_SIZE]; uint64 ROMlib_sizes[OFFSET_TABLE_SIZE] = {0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF}; #endif +DebuggerCallbacks syn68k_debugger_callbacks = {0,0}; /* This function initializes syn68k. Call it exactly once, before any * other syn68k calls. DOS_INT_FLAG_ADDR is the conventional memory From 7dd043cfb08d42c7528f092847cb0a49187eeece Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Fri, 8 Feb 2019 09:37:08 +0100 Subject: [PATCH 2/5] first attempt (wrong) --- runtime/blockinfo.c | 10 ++++++++++ runtime/syn68k_header.h | 11 ++++++++--- runtime/translate.c | 28 +++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/runtime/blockinfo.c b/runtime/blockinfo.c index d9eb9e0..370d4b6 100644 --- a/runtime/blockinfo.c +++ b/runtime/blockinfo.c @@ -83,6 +83,16 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) /* Move on to the next instruction. */ old_code = code; code += insn_size; + + if(syn68k_debugger_callbacks.getNextBreakpoint) + { + uint32_t addr = US_TO_SYN68K(old_code); + uint32_t break_addr = syn68k_debugger_callbacks.getNextBreakpoint(addr); + if(break_addr <= addr + insn_size) + { + break; + } + } } while (!map->ends_block); diff --git a/runtime/syn68k_header.h b/runtime/syn68k_header.h index 7f4327c..87fe61e 100644 --- a/runtime/syn68k_header.h +++ b/runtime/syn68k_header.h @@ -566,10 +566,15 @@ interpret_code1 (const uint16 *code, CPUState *cpu_state_ptr, const void ***out_ CASE_POSTAMBLE (ROUND_UP (PTR_WORDS + 1)); #endif /* !GENERATE_NATIVE_CODE */ - /* Reserved - two word NOP. */ + /* Debugger breakpoint or single-step. */ CASE (0x0002) - /* Historical cruft. */ - CASE_PREAMBLE ("Reserved: 2 word NOP", "", "", "", "") + CASE_PREAMBLE ("Debugger breakpoint or single-step", "", "", "", "") + if(syn68k_debugger_callbacks.debugger) + { + SAVE_CPU_STATE (); + code = code_lookup( syn68k_debugger_callbacks.debugger(*(uint32_t*)code) ); + LOAD_CPU_STATE (); + } CASE_POSTAMBLE (ROUND_UP (PTR_WORDS + 1)); /* Reserved - skip stub NOP. */ diff --git a/runtime/translate.c b/runtime/translate.c index e725b70..b68bc22 100644 --- a/runtime/translate.c +++ b/runtime/translate.c @@ -69,6 +69,8 @@ typedef struct static void compute_maps_and_ccs (Block *b, MapAndCC *m, const TempBlockInfo *tbi); +static inline uint16 * output_opcode (uint16 *code, uint32 opcode); + /* Compiles a block at a specified address and returns a mask indicating * which cc bits must be valid on entry to this block. The block is placed @@ -317,6 +319,19 @@ generate_code (Block *b, TempBlockInfo *tbi, BOOL try_native_p) /* Loop over all instructions, in forwards order, and compile them. */ m68k_code = SYN68K_TO_US (b->m68k_start_address); + + if(syn68k_debugger_callbacks.getNextBreakpoint) + { + uint32_t break_addr = syn68k_debugger_callbacks.getNextBreakpoint(b->m68k_start_address); + if(b->m68k_start_address == break_addr) + { + uint8_t *p = (uint8_t*)output_opcode((uint16*)(code + num_code_bytes), 0x0002); + *(uint32_t*)p = b->m68k_start_address; + p += 4; + num_code_bytes = p - code; + } + } + #ifdef GENERATE_NATIVE_CODE prev_native_p = TRUE; /* So n->s stub will be generated if necessary. */ #endif /* GENERATE_NATIVE_CODE */ @@ -517,7 +532,18 @@ generate_code (Block *b, TempBlockInfo *tbi, BOOL try_native_p) prev_native_p = native_p; #endif /* GENERATE_NATIVE_CODE */ } - + if(syn68k_debugger_callbacks.getNextBreakpoint) + { + uint32_t addr = US_TO_SYN68K(m68k_code); + uint32_t break_addr = syn68k_debugger_callbacks.getNextBreakpoint(addr - 1); + if(break_addr == addr) + { + uint8_t *p = (uint8_t*)output_opcode((uint16*)(code + num_code_bytes), 0x0002); + *(uint32_t*)p = b->m68k_start_address; + p += 4; + num_code_bytes = p - code; + } + } /* Copy the code we just created over to the block. We allocate a little * extra space because we prepend all compiled code with the big-endian * 68k PC of the first instruction, in case we hit an interrupt when From ba4763e4e953a4f31a80273d49f70c184c8fb1a2 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sat, 9 Feb 2019 09:39:01 +0100 Subject: [PATCH 3/5] add .editorconfig --- .editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..32f0eb5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*] +end_of_line = lf +insert_final_newline = true +indent_style = tab +tab_width = 8 +indent_width = 2 +charset = utf-8 From d228def2ca38c3e0fce33ebecf5dcea3a14c47b9 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sat, 9 Feb 2019 09:44:28 +0100 Subject: [PATCH 4/5] make breakpoints work --- runtime/blockinfo.c | 36 +++++++++++++++++++++++------------- runtime/include/blockinfo.h | 2 ++ runtime/syn68k_header.h | 9 ++++++++- runtime/translate.c | 29 +++++++---------------------- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/runtime/blockinfo.c b/runtime/blockinfo.c index 370d4b6..2e95292 100644 --- a/runtime/blockinfo.c +++ b/runtime/blockinfo.c @@ -24,6 +24,7 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) int clobbered = 0, may_set = 0, may_not_set = ALL_CCS, needed = 0; int next_array_size; const OpcodeMappingInfo *map = NULL; + uint32_t break_addr = 0xFFFFFFFF; /* Initialize the next offset array. This lets us step through this * code forwards when we actually get around to compiling it. @@ -31,6 +32,13 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) temp->num_68k_instrs = 0; next_array_size = 16; temp->next_instr_offset = (int8 *) xmalloc (next_array_size * sizeof (int8)); + temp->break_at_end = false; + + if(syn68k_debugger_callbacks.getNextBreakpoint) + { + uint32_t addr = US_TO_SYN68K(code); + break_addr = syn68k_debugger_callbacks.getNextBreakpoint(addr); + } /* Loop over all instructions in the block and determine information * about how this block deals with CC bits. @@ -40,8 +48,12 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) { int insn_size; unsigned m68k_op; + uint32_t addr = US_TO_SYN68K (code); + + if (addr >= break_addr) + break; - m68k_op = READUW (US_TO_SYN68K (code)); + m68k_op = READUW (addr); map = &opcode_map_info[opcode_map_index[m68k_op]]; #if 0 @@ -83,24 +95,22 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) /* Move on to the next instruction. */ old_code = code; code += insn_size; - - if(syn68k_debugger_callbacks.getNextBreakpoint) - { - uint32_t addr = US_TO_SYN68K(old_code); - uint32_t break_addr = syn68k_debugger_callbacks.getNextBreakpoint(addr); - if(break_addr <= addr + insn_size) - { - break; - } - } } while (!map->ends_block); /* Terminate the array with a 0 offset. */ temp->next_instr_offset[temp->num_68k_instrs] = 0; - /* Figure out where this block goes (if possible). */ - determine_next_block_addresses (old_code, temp, map); + if (US_TO_SYN68K (code) >= break_addr) + { + temp->num_child_blocks = 0; + temp->break_at_end = true; + } + else + { + /* Figure out where this block goes (if possible). */ + determine_next_block_addresses (old_code, temp, map); + } /* Record the block information we've computed. */ b->cc_clobbered = clobbered; diff --git a/runtime/include/blockinfo.h b/runtime/include/blockinfo.h index 88c71d1..e2bd787 100644 --- a/runtime/include/blockinfo.h +++ b/runtime/include/blockinfo.h @@ -2,12 +2,14 @@ #define _blockinfo_h_ #include "block.h" +#include typedef struct { uint32 child[2]; /* m68k addresses of m68k code following this blk. */ int16 num_child_blocks; /* # of child addrs we can know at translate time. */ uint16 num_68k_instrs; int8 *next_instr_offset; /* word offset to next instr; 0 iff last instr. */ + bool break_at_end; } TempBlockInfo; extern void compute_block_info (Block *b, const uint16 *code, diff --git a/runtime/syn68k_header.h b/runtime/syn68k_header.h index 87fe61e..3291196 100644 --- a/runtime/syn68k_header.h +++ b/runtime/syn68k_header.h @@ -575,7 +575,14 @@ interpret_code1 (const uint16 *code, CPUState *cpu_state_ptr, const void ***out_ code = code_lookup( syn68k_debugger_callbacks.debugger(*(uint32_t*)code) ); LOAD_CPU_STATE (); } - CASE_POSTAMBLE (ROUND_UP (PTR_WORDS + 1)); + else + { + // We should never get here, (callbacks.getNextBreakpoint set + // but callbacks.debugger cleared). But if we do, it's not a prolbem. + code = code_lookup(*(uint32_t*)code); + } + + CASE_POSTAMBLE (ROUND_UP (PTR_WORDS)); /* Reserved - skip stub NOP. */ CASE (0x0003) diff --git a/runtime/translate.c b/runtime/translate.c index b68bc22..43c225c 100644 --- a/runtime/translate.c +++ b/runtime/translate.c @@ -320,18 +320,6 @@ generate_code (Block *b, TempBlockInfo *tbi, BOOL try_native_p) /* Loop over all instructions, in forwards order, and compile them. */ m68k_code = SYN68K_TO_US (b->m68k_start_address); - if(syn68k_debugger_callbacks.getNextBreakpoint) - { - uint32_t break_addr = syn68k_debugger_callbacks.getNextBreakpoint(b->m68k_start_address); - if(b->m68k_start_address == break_addr) - { - uint8_t *p = (uint8_t*)output_opcode((uint16*)(code + num_code_bytes), 0x0002); - *(uint32_t*)p = b->m68k_start_address; - p += 4; - num_code_bytes = p - code; - } - } - #ifdef GENERATE_NATIVE_CODE prev_native_p = TRUE; /* So n->s stub will be generated if necessary. */ #endif /* GENERATE_NATIVE_CODE */ @@ -532,18 +520,15 @@ generate_code (Block *b, TempBlockInfo *tbi, BOOL try_native_p) prev_native_p = native_p; #endif /* GENERATE_NATIVE_CODE */ } - if(syn68k_debugger_callbacks.getNextBreakpoint) + + if (tbi->break_at_end) { - uint32_t addr = US_TO_SYN68K(m68k_code); - uint32_t break_addr = syn68k_debugger_callbacks.getNextBreakpoint(addr - 1); - if(break_addr == addr) - { - uint8_t *p = (uint8_t*)output_opcode((uint16*)(code + num_code_bytes), 0x0002); - *(uint32_t*)p = b->m68k_start_address; - p += 4; - num_code_bytes = p - code; - } + uint8_t *p = (uint8_t*)output_opcode((uint16*)(code + num_code_bytes), 0x0002); + *(uint32_t*)p = US_TO_SYN68K(m68k_code); + p += 4; + num_code_bytes = p - code; } + /* Copy the code we just created over to the block. We allocate a little * extra space because we prepend all compiled code with the big-endian * 68k PC of the first instruction, in case we hit an interrupt when From 67c7efac5c48bad5ed8fbb8a602ec502c536cc4c Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sat, 16 Feb 2019 17:40:19 +0100 Subject: [PATCH 5/5] fix single-stepping over branch instructions --- runtime/blockinfo.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/blockinfo.c b/runtime/blockinfo.c index 2e95292..dc47a30 100644 --- a/runtime/blockinfo.c +++ b/runtime/blockinfo.c @@ -25,6 +25,7 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) int next_array_size; const OpcodeMappingInfo *map = NULL; uint32_t break_addr = 0xFFFFFFFF; + bool breakpoint = false; /* Initialize the next offset array. This lets us step through this * code forwards when we actually get around to compiling it. @@ -51,7 +52,10 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) uint32_t addr = US_TO_SYN68K (code); if (addr >= break_addr) - break; + { + breakpoint = true; + break; + } m68k_op = READUW (addr); map = &opcode_map_info[opcode_map_index[m68k_op]]; @@ -101,7 +105,7 @@ compute_block_info (Block *b, const uint16 *code, TempBlockInfo *temp) /* Terminate the array with a 0 offset. */ temp->next_instr_offset[temp->num_68k_instrs] = 0; - if (US_TO_SYN68K (code) >= break_addr) + if (breakpoint) { temp->num_child_blocks = 0; temp->break_at_end = true;