diff -urN fuse-0.4.2/Makefile.in fuse-0.4.2_debugger/Makefile.in --- fuse-0.4.2/Makefile.in Tue Jul 23 20:17:43 2002 +++ fuse-0.4.2_debugger/Makefile.in Tue Jul 23 20:06:09 2002 @@ -76,7 +76,7 @@ SUBDIRS = lib libspectrum man myglib perl roms ui utils widget z80 -fuse_SOURCES = ay.c display.c event.c fuse.c keyboard.c keysyms.c machine.c osssound.c rzx.c settings.c snapshot.c sound.c spec128.c spec48.c specplus2.c specplus3.c spectrum.c sunsound.c tape.c timer.c uidisplay.c utils.c joystick.c printer.c +fuse_SOURCES = ay.c display.c debugger.c event.c fuse.c keyboard.c keysyms.c machine.c osssound.c rzx.c settings.c snapshot.c sound.c spec128.c spec48.c specplus2.c specplus3.c spectrum.c sunsound.c tape.c timer.c uidisplay.c utils.c joystick.c printer.c BUILT_SOURCES = keysyms.c @@ -85,7 +85,7 @@ LDADD = @GLIB_LIBS@ @GTK_LIBS@ libspectrum/libspectrum.a myglib/libmyglib.a ui/aalib/libuiaalib.a ui/fb/libuifb.a ui/gtk/libuigtk.a ui/svga/libuisvga.a ui/xlib/libuixlib.a widget/libwidget.a z80/libz80.a -noinst_HEADERS = ay.h display.h event.h fuse.h keyboard.h keysyms.h machine.h osssound.h rzx.h settings.h snapshot.h sound.h spec128.h spec48.h specplus2.h specplus3.h spectrum.h sunsound.h tape.h timer.h types.h utils.h joystick.h printer.h +noinst_HEADERS = ay.h display.h debugger.h event.h fuse.h keyboard.h keysyms.h machine.h osssound.h rzx.h settings.h snapshot.h sound.h spec128.h spec48.h specplus2.h specplus3.h spectrum.h sunsound.h tape.h timer.h types.h utils.h joystick.h printer.h EXTRA_DIST = AUTHORS README THANKS hacking/coding_style.txt hacking/ui.txt keysyms.dat keysyms.pl @@ -105,7 +105,7 @@ X_LIBS = @X_LIBS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ -fuse_OBJECTS = ay.o display.o event.o fuse.o keyboard.o keysyms.o \ +fuse_OBJECTS = ay.o display.o debugger.o event.o fuse.o keyboard.o keysyms.o \ machine.o osssound.o rzx.o settings.o snapshot.o sound.o spec128.o \ spec48.o specplus2.o specplus3.o spectrum.o sunsound.o tape.o timer.o \ uidisplay.o utils.o joystick.o printer.o @@ -378,6 +378,7 @@ printer.h sound.h display.o: display.c config.h display.h types.h event.h machine.h ay.h \ spectrum.h ui/ui.h ui/uidisplay.h +debugger.o: debugger.c event.o: event.c config.h display.h types.h event.h machine.h ay.h \ spectrum.h rzx.h libspectrum/rzx.h libspectrum/libspectrum.h \ tape.h ui/ui.h diff -urN fuse-0.4.2/debugger.c fuse-0.4.2_debugger/debugger.c --- fuse-0.4.2/debugger.c Thu Jan 1 01:00:00 1970 +++ fuse-0.4.2_debugger/debugger.c Tue Jul 23 20:01:38 2002 @@ -0,0 +1,237 @@ +/* debugger.c + + Copyright (c) 2002 Anders Holmberg + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Author contact information: + Mail : aagholmberg@yahoo.se + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "machine.h" +#include "spectrum.h" +#include "settings.h" +#include "debugger.h" + +#include "z80/z80.h" +#include "z80/z80_macros.h" + +/* ---------------------------------------------------------------------------- + * Defines + * ---------------------------------------------------------------------------- */ +#define PORT 3490 +#define MAXDATASIZE 100 + +/* ---------------------------------------------------------------------------- + * Local variables + * ---------------------------------------------------------------------------- */ +static int sockfd; +static struct hostent *he; +static struct sockaddr_in addr; // connector's address information +static struct sockaddr_in rec_addr; +static char hostname[]="127.0.0.1"; +static debugger_mode_t debugger_mode = not_connected; +static breakpoint_mode_t breakpoint_mode = not_active; +static char buffer[100]; +static char debugger_msg[400]; +static int breakpoint_addr = 0; + +/* ---------------------------------------------------------------------------- + * Local functions + * ---------------------------------------------------------------------------- */ +void build_debugger_msg( int user_addr ) +{ + int i, mem_addr; + + sprintf( &debugger_msg[0], "%02x", A ); + sprintf( &debugger_msg[2], "%02x", F ); + sprintf( &debugger_msg[4], "%02x", B ); + sprintf( &debugger_msg[6], "%02x", C ); + sprintf( &debugger_msg[8], "%02x", D ); + sprintf( &debugger_msg[10], "%02x", E ); + sprintf( &debugger_msg[12], "%02x", H ); + sprintf( &debugger_msg[14], "%02x", L ); + sprintf( &debugger_msg[16], "%02x", IXH ); + sprintf( &debugger_msg[18], "%02x", IXL ); + sprintf( &debugger_msg[20], "%02x", IYH ); + sprintf( &debugger_msg[22], "%02x", IYL ); + sprintf( &debugger_msg[24], "%02x", SPH ); + sprintf( &debugger_msg[26], "%02x", SPL ); + sprintf( &debugger_msg[28], "%02x", PCH ); + sprintf( &debugger_msg[30], "%02x", PCL ); + sprintf( &debugger_msg[32], "%02x", I ); + sprintf( &debugger_msg[34], "%02x", R ); + sprintf( &debugger_msg[36], "%02x", IFF1 ); + sprintf( &debugger_msg[38], "%02x", IFF2 ); + sprintf( &debugger_msg[40], "%02x", IM ); + sprintf( &debugger_msg[42], "%04x", tstates ); + + if( user_addr < 0 ) + mem_addr = PC; + else + mem_addr = user_addr; + + sprintf( &debugger_msg[46], "%04x", mem_addr ); + + for( i=0; i<16*10; i++ ) + sprintf( &debugger_msg[50+i*2], "%02x", readbyte( mem_addr + i ) ); +} + +/* ---------------------------------------------------------------------------- + * External functions + * ---------------------------------------------------------------------------- */ + +void debugger_init() +{ + if( !settings_current.debugger ) + return; + + sockfd = socket( AF_INET, SOCK_DGRAM, 0 ); + if( sockfd == -1 ) + { + perror( "Socket error" ); + debugger_mode = not_connected; + return; + } + + he = gethostbyname( hostname ); + if( he == 0 ) + { + perror( "Hostname error" ); + debugger_mode = not_connected; + return; + } + + memcpy(&addr.sin_addr,he->h_addr, he->h_length ); + addr.sin_family = AF_INET; + addr.sin_port = htons(3490); + + rec_addr.sin_addr.s_addr = INADDR_ANY; + rec_addr.sin_family = AF_INET; + rec_addr.sin_port = htons(3491); + + if( bind( sockfd, (struct sockaddr *)&rec_addr, sizeof( rec_addr ) ) < 0 ) + { + perror( "Bind error" ); + debugger_mode = not_connected; + return; + } + + /* Make the socket a non-blocking socket */ + fcntl( sockfd, F_SETFL, O_NONBLOCK ); + + debugger_mode = executing; +} + +debugger_action_t debugger_check_socket() +{ + int nr; + unsigned int mem_addr; + + /* Is the UDP socket really configured correctly */ + if( debugger_mode == not_connected ) + return no_action; + + /* Try to read data from socket (non-blocking) */ + nr = read( sockfd, (void *)buffer, sizeof( buffer ) ); + + /* Did not get any data this time - better luck next time! */ + if( nr <= 0 ) + { + return no_action; + } + + buffer[nr] = '\0'; + + /* Check command */ + if( buffer[0] == 'h' ) + { + debugger_mode = halted; + } + else if( buffer[0] == 'c' ) + { + debugger_mode = executing; + } + else if( buffer[0] == 'i' ) + { + build_debugger_msg( -1 ); + sendto( sockfd, (void *)debugger_msg, 370, 0, (struct sockaddr *)&addr, sizeof( addr ) ); + } + else if( buffer[0] == 'm' ) + { + mem_addr = (int)strtol( &buffer[1], NULL, 16 ); + build_debugger_msg( mem_addr ); + sendto( sockfd, (void *)debugger_msg, 370, 0, (struct sockaddr *)&addr, sizeof( addr ) ); + } + else if( buffer[0] =='b' && buffer[1] =='d' ) + { + breakpoint_mode = not_active; + } + else if( buffer[0] == 'b' && buffer[1]!='x' ) + { + mem_addr = (int)strtol( &buffer[1], NULL, 16 ); + breakpoint_mode = active; + breakpoint_addr = mem_addr; + } + else if( buffer[0] == 's' ) + { + /* Make sure we are in halted mode when single stepping */ + debugger_mode = halted; + return single_step; + } + else + { + } + + return no_action; + +} + +void debugger_end() +{ + if( settings_current.debugger ) + close(sockfd); +} + +debugger_mode_t debugger_check_mode() +{ + return debugger_mode; +} + +void debugger_check_breakpoint() +{ + if( breakpoint_mode == active ) + { + if( breakpoint_addr == PC ) + { + printf( "BREAKPOINT TRIGGERED AT 0x%04x\n", breakpoint_addr ); + debugger_mode = halted; + } + } +} + + diff -urN fuse-0.4.2/debugger.h fuse-0.4.2_debugger/debugger.h --- fuse-0.4.2/debugger.h Thu Jan 1 01:00:00 1970 +++ fuse-0.4.2_debugger/debugger.h Tue Jul 23 20:01:38 2002 @@ -0,0 +1,32 @@ + + +#ifndef __DEBUGGER_H__ +#define __DEBUGGER_H__ + +/* Mode of debugging */ +typedef enum debugger_mode_t +{ + not_connected,halted, executing +} debugger_mode_t; + + +typedef enum debugger_action_t +{ + no_action, single_step +} debugger_action_t; + +typedef enum breakpoint_mode_t +{ + active, not_active +} breakpoint_mode_t; + +void debugger_end(); +void debugger_init(); +void debugger_check_breakpoint(); +debugger_action_t debugger_check_socket(); +debugger_mode_t debugger_check_mode(); + +#endif + + + diff -urN fuse-0.4.2/fuse.c fuse-0.4.2_debugger/fuse.c --- fuse-0.4.2/fuse.c Tue Jul 23 20:17:43 2002 +++ fuse-0.4.2_debugger/fuse.c Tue Jul 23 20:01:38 2002 @@ -44,6 +44,7 @@ #include "ui/ui.h" #include "widget/widget.h" #include "z80/z80.h" +#include "debugger.h" /* What name were we called under? */ char* fuse_progname; @@ -143,6 +144,8 @@ rzx_start_recording( settings_current.record_file ); } + debugger_init(); + fuse_emulation_paused = 0; return 0; @@ -253,6 +256,8 @@ widget_end(); + debugger_end(); + return 0; } diff -urN fuse-0.4.2/settings.c fuse-0.4.2_debugger/settings.c --- fuse-0.4.2/settings.c Tue Jul 23 20:17:43 2002 +++ fuse-0.4.2_debugger/settings.c Tue Jul 23 20:01:38 2002 @@ -63,6 +63,8 @@ /* Fill the settings structure with sensible defaults */ int settings_defaults( settings_info *settings ) { + settings->debugger = 0; + settings->issue2 = 0; settings->joy_kempston = 0; settings->tape_traps = 1; @@ -101,6 +103,9 @@ struct option long_options[] = { + { "debugger", 0, &(settings->debugger), 1 }, + { "no-debugger", 0, &(settings->debugger), 0 }, + { "machine", 1, NULL, 'm' }, { "snapshot", 1, NULL, 's' }, @@ -197,6 +202,7 @@ /* Copy one settings object to another */ int settings_copy( settings_info *dest, settings_info *src ) { + dest->debugger = src->debugger; dest->issue2 = src->issue2; dest->joy_kempston = src->joy_kempston; dest->tape_traps = src->tape_traps; diff -urN fuse-0.4.2/settings.h fuse-0.4.2_debugger/settings.h --- fuse-0.4.2/settings.h Tue Jul 23 20:17:43 2002 +++ fuse-0.4.2_debugger/settings.h Tue Jul 23 20:01:38 2002 @@ -33,6 +33,7 @@ /* General options */ + int debugger; /* Is the debugger activated? */ int issue2; /* Issue 2 keyboard emulation? */ int joy_kempston; /* Kempston joystick emulation? */ int tape_traps; /* Use tape loading traps? */ diff -urN fuse-0.4.2/z80/z80_ops.c fuse-0.4.2_debugger/z80/z80_ops.c --- fuse-0.4.2/z80/z80_ops.c Tue Jul 23 20:17:43 2002 +++ fuse-0.4.2_debugger/z80/z80_ops.c Tue Jul 23 20:01:38 2002 @@ -1,3 +1,5 @@ +/* ex: set ts=2: */ + /* z80_ops.c: Process the next opcode Copyright (c) 1999-2000,2002 Philip Kendall @@ -25,7 +27,7 @@ */ #include - +#include #include #include "event.h" @@ -37,6 +39,8 @@ #include "z80_macros.h" +#include "debugger.h" + #ifndef HAVE_ENOUGH_MEMORY static void z80_cbxx(BYTE opcode2); static void z80_ddxx(BYTE opcode2); @@ -49,10 +53,32 @@ void z80_do_opcodes() { + /* There is a very small chance that a single step can be missed (2 single step + commands has to be sent with appr. 20 ms interval at the exact right moment) + but we do not care! */ + if( settings_current.debugger ) + { + (void)debugger_check_socket(); + } + while(tstates < event_next_event ) { BYTE opcode; + if( settings_current.debugger ) + { + debugger_check_breakpoint(); + + while( debugger_check_mode() == halted ) + { + if( debugger_check_socket() == single_step ) + { + break; + } + sleep( 1 ); /* Change this to 100ms */ + } + } + /* If we're due an interrupt from RZX playback, generate one */ if( rzx_playback && rzx_instructions >= rzx.frames[ rzx_current_frame ].instructions ) {