changeset 2676:7e86ec94c899

Implement breakpoints in new 68K core
author Michael Pavone <pavone@retrodev.com>
date Sat, 15 Mar 2025 23:15:05 -0700
parents dbff641a33df
children 2df04125ac78
files backend.h cpu_dsl.py debug.c debug.h gdb_remote.c gdb_remote.h m68k.cpu m68k_core.c m68k_core.h m68k_core_x86.c m68k_internal.h m68k_util.c
diffstat 12 files changed, 85 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/backend.h	Fri Mar 14 01:18:11 2025 -0700
+++ b/backend.h	Sat Mar 15 23:15:05 2025 -0700
@@ -84,6 +84,12 @@
 	uint8_t            align_error_mask;
 } cpu_options;
 
+typedef void (*debug_handler)(void *context, uint32_t pc);
+typedef struct {
+	debug_handler handler;
+	uint32_t      address;
+} breakpoint;
+
 typedef uint8_t * (*native_addr_func)(void * context, uint32_t address);
 
 typedef uint16_t (*interp_read_16)(uint32_t address, void *context, void *data);
--- a/cpu_dsl.py	Fri Mar 14 01:18:11 2025 -0700
+++ b/cpu_dsl.py	Sat Mar 15 23:15:05 2025 -0700
@@ -2056,6 +2056,8 @@
 		self.interrupt = info.get('interrupt', [None])[0]
 		self.sync_cycle = info.get('sync_cycle', [None])[0]
 		self.includes = info.get('include', [])
+		self.pc_reg = info.get('pc_reg', [None])[0]
+		self.pc_offset = info.get('pc_offset', [0])[0]
 		self.flags = flags
 		self.lastDst = None
 		self.scopes = []
@@ -2088,6 +2090,8 @@
 		hFile.write('\n#define {0}_'.format(macro))
 		hFile.write('\n#include <stdio.h>')
 		hFile.write('\n#include "backend.h"')
+		if self.pc_reg:
+			hFile.write('\n#include "tern.h"')
 		hFile.write(f'\n\ntypedef struct {self.prefix}options {self.prefix}options;')
 		hFile.write(f'\n\ntypedef struct {self.prefix}context {self.prefix}context;')
 		for decl in self.declares:
@@ -2100,6 +2104,8 @@
 		hFile.write('\n};')
 		hFile.write(f'\n\nstruct {self.prefix}context {{')
 		hFile.write(f'\n\t{self.prefix}options *opts;')
+		if self.pc_reg:
+			hFile.write('\n\ttern_node *breakpoints;');
 		self.regs.writeHeader(otype, hFile)
 		hFile.write('\n};')
 		hFile.write('\n')
@@ -2201,6 +2207,36 @@
 				pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
 				pieces.append('\n{')
 				pieces.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle))
+				if self.pc_reg:
+					pieces.append('\n\tif (context->breakpoints) {')
+					pieces.append('\n\t\twhile (context->cycles < target_cycle)')
+					pieces.append('\n\t\t{')
+					if self.interrupt in self.subroutines:
+						pieces.append('\n\t\t\tif (context->cycles >= context->sync_cycle) {')
+						pieces.append(f'\n\t\t\t\t{self.sync_cycle}(context, target_cycle);')
+						pieces.append('\n\t\t\t}')
+						self.meta = {}
+						self.temp = {}
+						intpieces = []
+						self.subroutines[self.interrupt].inline(self, [], intpieces, otype, None)
+						for size in self.temp:
+							pieces.append('\n\t\t\tuint{sz}_t gen_tmp{sz}__;'.format(sz=size))
+						pieces += intpieces
+					if self.pc_offset:
+						pieces.append(f'\n\t\t\tuint32_t debug_pc = context->{self.pc_reg} - {self.pc_offset};')
+						pc_reg = 'debug_pc'
+					else:
+						pc_reg = 'context->' + self.pc_reg
+					pieces.append('\n\t\t\tchar key_buf[6];')
+					pieces.append(f'\n\t\t\tdebug_handler handler = tern_find_ptr(context->breakpoints, tern_int_key({pc_reg}, key_buf));')
+					pieces.append('\n\t\t\tif (handler) {')
+					pieces.append(f'\n\t\t\t\thandler(context, {pc_reg});')
+					pieces.append('\n\t\t\t}')
+					self.meta = {}
+					self.temp = {}
+					self.subroutines[self.body].inline(self, [], pieces, otype, None)
+					pieces.append('\n\t}')
+					pieces.append('\n\t} else {')
 				pieces.append('\n\twhile (context->cycles < target_cycle)')
 				pieces.append('\n\t{')
 				if self.interrupt in self.subroutines:
@@ -2218,6 +2254,8 @@
 				self.temp = {}
 				self.subroutines[self.body].inline(self, [], pieces, otype, None)
 				pieces.append('\n\t}')
+				if self.pc_reg:
+					pieces.append('\n\t}')
 				pieces.append('\n}')
 			body.append('\nstatic void unimplemented({pre}context *context, uint32_t target_cycle)'.format(pre = self.prefix))
 			body.append('\n{')
--- a/debug.c	Fri Mar 14 01:18:11 2025 -0700
+++ b/debug.c	Sat Mar 15 23:15:05 2025 -0700
@@ -5559,11 +5559,12 @@
 
 #endif
 
-void debugger(m68k_context * context, uint32_t address)
+void debugger(void *vcontext, uint32_t address)
 {
 	static char last_cmd[1024];
 	char input_buf[1024];
 	m68kinst inst;
+	m68k_context *context = vcontext;
 
 	init_terminal();
 
@@ -5656,11 +5657,9 @@
 		genesis_context *gen = context->system;
 		vdp_force_update_framebuffer(gen->vdp);
 	}
-#ifndef NEW_CORE
 	uint32_t after = m68k_decode(m68k_instruction_fetch, context, &inst, address);
 	root->after = after;
 	root->inst = &inst;
-#endif
 	for (disp_def * cur = root->displays; cur; cur = cur->next) {
 		char format_str[8];
 		make_format_str(format_str, cur->format);
--- a/debug.h	Fri Mar 14 01:18:11 2025 -0700
+++ b/debug.h	Sat Mar 15 23:15:05 2025 -0700
@@ -219,7 +219,7 @@
 bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index);
 void add_display(disp_def ** head, uint32_t *index, char format_char, char * param);
 void remove_display(disp_def ** head, uint32_t index);
-void debugger(m68k_context * context, uint32_t address);
+void debugger(void * vcontext, uint32_t address);
 z80_context * zdebugger(z80_context * context, uint16_t address);
 void print_m68k_help();
 void print_z80_help();
--- a/gdb_remote.c	Fri Mar 14 01:18:11 2025 -0700
+++ b/gdb_remote.c	Sat Mar 15 23:15:05 2025 -0700
@@ -501,8 +501,9 @@
 	fatal_error("Command %s is not implemented, exiting...\n", command);
 }
 
-void  gdb_debug_enter(m68k_context * context, uint32_t pc)
+void  gdb_debug_enter(void *vcontext, uint32_t pc)
 {
+	m68k_context *context = vcontext;
 	dfprintf(stderr, "Entered debugger at address %X\n", pc);
 	if (expect_break_response) {
 		if (context->wp_hit) {
--- a/gdb_remote.h	Fri Mar 14 01:18:11 2025 -0700
+++ b/gdb_remote.h	Sat Mar 15 23:15:05 2025 -0700
@@ -3,6 +3,6 @@
 #include "genesis.h"
 
 void gdb_remote_init(void);
-void gdb_debug_enter(m68k_context * context, uint32_t pc);
+void gdb_debug_enter(void *vcontext, uint32_t pc);
 
 #endif //GDB_REMOTE_H_
--- a/m68k.cpu	Fri Mar 14 01:18:11 2025 -0700
+++ b/m68k.cpu	Sat Mar 15 23:15:05 2025 -0700
@@ -6,6 +6,8 @@
 	interrupt m68k_interrupt
 	include m68k_util.c
 	sync_cycle m68k_sync_cycle
+	pc_reg pc
+	pc_offset 2
 	
 declare
 	typedef m68k_context *(sync_fun)(m68k_context * context, uint32_t address);
@@ -18,6 +20,9 @@
 	void m68k_serialize(m68k_context *context, uint32_t pc, serialize_buffer *buf);
 	void m68k_deserialize(deserialize_buffer *buf, void *vcontext);
 	void start_68k_context(m68k_context *context, uint32_t pc);
+	void insert_breakpoint(m68k_context *context, uint32_t address, debug_handler handler);
+	void remove_breakpoint(m68k_context *context, uint32_t address);
+	uint16_t m68k_instruction_fetch(uint32_t address, void *vcontext);
 	define NUM_MEM_AREAS 10
 	define M68K_OPT_BROKEN_READ_MODIFY 1
 	define INT_PENDING_SR_CHANGE 254
@@ -27,8 +32,6 @@
 	define m68k_options_free free
 	define m68k_handle_code_write(address, context)
 	define resume_68k(context) m68k_execute(context, context->target_cycle)
-	define insert_breakpoint(context, address, handler)
-	define remove_breakpoint(context, address)
 	define m68k_add_watchpoint(context, address, size)
 	define m68k_remove_watchpoint(context, address, size)
 
--- a/m68k_core.c	Fri Mar 14 01:18:11 2025 -0700
+++ b/m68k_core.c	Sat Mar 15 23:15:05 2025 -0700
@@ -792,7 +792,7 @@
 	return 0xFFFF;
 }
 
-static m68k_debug_handler find_breakpoint(m68k_context *context, uint32_t address)
+static debug_handler find_breakpoint(m68k_context *context, uint32_t address)
 {
 	for (uint32_t i = 0; i < context->num_breakpoints; i++)
 	{
@@ -803,7 +803,7 @@
 	return NULL;
 }
 
-void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler)
+void insert_breakpoint(m68k_context * context, uint32_t address, debug_handler bp_handler)
 {
 	if (!find_breakpoint(context, address)) {
 		if (context->bp_storage == context->num_breakpoints) {
@@ -811,9 +811,9 @@
 			if (context->bp_storage < 4) {
 				context->bp_storage = 4;
 			}
-			context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(m68k_breakpoint));
+			context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(breakpoint));
 		}
-		context->breakpoints[context->num_breakpoints++] = (m68k_breakpoint){
+		context->breakpoints[context->num_breakpoints++] = (breakpoint){
 			.handler = bp_handler,
 			.address = address
 		};
@@ -823,7 +823,7 @@
 
 m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address)
 {
-	m68k_debug_handler handler = find_breakpoint(context, address);
+	debug_handler handler = find_breakpoint(context, address);
 	if (handler) {
 		handler(context, address);
 	} else {
@@ -1085,7 +1085,7 @@
 	code_ptr start = opts->gen.code.cur;
 	check_cycles_int(&opts->gen, inst->address);
 
-	m68k_debug_handler bp;
+	debug_handler bp;
 	if ((bp = find_breakpoint(context, inst->address))) {
 		m68k_breakpoint_patch(context, inst->address, bp, start);
 	}
--- a/m68k_core.h	Fri Mar 14 01:18:11 2025 -0700
+++ b/m68k_core.h	Sat Mar 15 23:15:05 2025 -0700
@@ -73,13 +73,6 @@
 	code_word       prologue_start;
 } m68k_options;
 
-typedef void (*m68k_debug_handler)(m68k_context *context, uint32_t pc);
-
-typedef struct {
-	m68k_debug_handler handler;
-	uint32_t           address;
-} m68k_breakpoint;
-
 typedef struct {
 	uint32_t start;
 	uint32_t end;
@@ -112,7 +105,7 @@
 	void            *system;
 	void            *host_sp_entry;
 	void            *stack_storage[M68K_STACK_STORAGE];
-	m68k_breakpoint *breakpoints;
+	breakpoint      *breakpoints;
 	uint32_t        num_breakpoints;
 	uint32_t        bp_storage;
 	uint32_t        watchpoint_min;
@@ -141,7 +134,7 @@
 m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler);
 void m68k_reset(m68k_context * context);
 void m68k_options_free(m68k_options *opts);
-void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler);
+void insert_breakpoint(m68k_context * context, uint32_t address, debug_handler bp_handler);
 void remove_breakpoint(m68k_context * context, uint32_t address);
 void m68k_add_watchpoint(m68k_context *context, uint32_t address, uint32_t size);
 void m68k_remove_watchpoint(m68k_context *context, uint32_t address, uint32_t size);
--- a/m68k_core_x86.c	Fri Mar 14 01:18:11 2025 -0700
+++ b/m68k_core_x86.c	Sat Mar 15 23:15:05 2025 -0700
@@ -2563,7 +2563,7 @@
 	}
 }
 
-void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr)
+void m68k_breakpoint_patch(m68k_context *context, uint32_t address, debug_handler bp_handler, code_ptr native_addr)
 {
 	m68k_options * opts = context->opts;
 	code_info native;
--- a/m68k_internal.h	Fri Mar 14 01:18:11 2025 -0700
+++ b/m68k_internal.h	Sat Mar 15 23:15:05 2025 -0700
@@ -35,7 +35,7 @@
 void m68k_set_last_prefetch(m68k_options *opts, uint32_t address);
 void translate_m68k_odd(m68k_options *opts, m68kinst *inst);
 void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst);
-void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr);
+void m68k_breakpoint_patch(m68k_context *context, uint32_t address, debug_handler bp_handler, code_ptr native_addr);
 void m68k_check_cycles_int_latch(m68k_options *opts);
 uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst);
 
--- a/m68k_util.c	Fri Mar 14 01:18:11 2025 -0700
+++ b/m68k_util.c	Sat Mar 15 23:15:05 2025 -0700
@@ -1,4 +1,7 @@
 #include <string.h>
+#ifdef DEBUG_DISASM
+#include "68kinst.h"
+#endif
 
 void m68k_read_8(m68k_context *context)
 {
@@ -14,14 +17,12 @@
 #endif
 }
 
-#ifdef DEBUG_DISASM
-#include "68kinst.h"
-static uint16_t debug_disasm_fetch(uint32_t address, void *vcontext)
+uint16_t m68k_instruction_fetch(uint32_t address, void *vcontext)
 {
 	m68k_context *context = vcontext;
-	return read_word(address, (void**)context->mem_pointers, &context->opts->gen, context);
+	return read_word(address, (void **)context->mem_pointers, &context->opts->gen, context);
 }
-#endif
+
 void m68k_read_16(m68k_context *context)
 {
 	context->cycles += 4 * context->opts->gen.clock_divider;
@@ -372,3 +373,17 @@
 	context->prefetch = context->scratch1;
 	context->pc += 2;
 }
+
+void insert_breakpoint(m68k_context *context, uint32_t address, debug_handler handler)
+{
+	char buf[6];
+	address &= context->opts->gen.address_mask;
+	context->breakpoints = tern_insert_ptr(context->breakpoints, tern_int_key(address, buf), handler);
+}
+
+void remove_breakpoint(m68k_context *context, uint32_t address)
+{
+	char buf[6];
+	address &= context->opts->gen.address_mask;
+	tern_delete(&context->breakpoints, tern_int_key(address, buf), NULL);
+}