From 2fc6cc22a29a53dc5127eafa2719d11e9bb38c42 Mon Sep 17 00:00:00 2001 From: Ian C Date: Thu, 22 Jan 2004 02:38:13 +0000 Subject: Updated with various bits from espec (memory menu, GUI, etc) --- src/Makefile | 24 +- src/gfx.c | 35 ++- src/gfx.h | 23 +- src/gui.c | 299 ++++++++++++++---- src/gui.h | 28 +- src/main.c | 69 ++++- src/memmenu.c | 949 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/memmenu.h | 13 +- src/util.c | 131 ++++++++ src/util.h | 73 +++++ src/zx81.c | 96 ++++-- src/zx81.h | 4 + 12 files changed, 1539 insertions(+), 205 deletions(-) create mode 100644 src/util.c create mode 100644 src/util.h diff --git a/src/Makefile b/src/Makefile index 96ed1c0..96c80bd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ # # ------------------------------------------------------------------------- # -# $Id: Makefile,v 1.7 2003-12-23 23:30:39 ianc Exp $ +# $Id: Makefile,v 1.8 2004-01-22 02:38:13 ianc Exp $ # @@ -38,6 +38,7 @@ SOURCE = main.c \ gfx.c \ gui.c \ memmenu.c \ + util.c \ exit.c OBJECTS = main.o \ @@ -46,6 +47,7 @@ OBJECTS = main.o \ gfx.o \ gui.o \ memmenu.o \ + util.o \ exit.o CFLAGS += -Iz80 `sdl-config --cflags` @@ -57,7 +59,7 @@ $(TARGET): $(OBJECTS) $(Z80LIB) $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(Z80LIB): z80/*.[ch] - cd z80; make ; cd .. + cd z80; make "EXTERNAL_CFLAGS=`sdl-config --cflags`" ; cd .. clean: rm -f $(TARGET) $(OBJECTS) core @@ -72,8 +74,9 @@ depend: main.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h main.o: /usr/include/sys/_types.h /usr/include/machine/_types.h -main.o: /usr/include/stdio.h /usr/local/include/SDL/SDL.h -main.o: /usr/local/include/SDL/SDL_main.h /usr/local/include/SDL/SDL_types.h +main.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h +main.o: /usr/local/include/SDL/SDL.h /usr/local/include/SDL/SDL_main.h +main.o: /usr/local/include/SDL/SDL_types.h main.o: /usr/local/include/SDL/SDL_getenv.h main.o: /usr/local/include/SDL/SDL_error.h main.o: /usr/local/include/SDL/begin_code.h @@ -153,10 +156,11 @@ gui.o: /usr/local/include/SDL/SDL_keyboard.h gui.o: /usr/local/include/SDL/SDL_keysym.h /usr/local/include/SDL/SDL_mouse.h gui.o: /usr/local/include/SDL/SDL_video.h /usr/local/include/SDL/SDL_mutex.h gui.o: /usr/local/include/SDL/SDL_quit.h /usr/local/include/SDL/SDL_version.h -gui.o: gfx.h exit.h +gui.o: gfx.h util.h exit.h memmenu.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h memmenu.o: /usr/include/sys/_types.h /usr/include/machine/_types.h -memmenu.o: /usr/include/string.h /usr/include/strings.h memmenu.h z80/z80.h +memmenu.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h +memmenu.o: /usr/include/ctype.h /usr/include/runetype.h memmenu.h z80/z80.h memmenu.o: zx81.h /usr/local/include/SDL/SDL.h memmenu.o: /usr/local/include/SDL/SDL_main.h memmenu.o: /usr/local/include/SDL/SDL_types.h @@ -164,7 +168,7 @@ memmenu.o: /usr/local/include/SDL/SDL_getenv.h memmenu.o: /usr/local/include/SDL/SDL_error.h memmenu.o: /usr/local/include/SDL/begin_code.h memmenu.o: /usr/local/include/SDL/close_code.h -memmenu.o: /usr/local/include/SDL/SDL_rwops.h /usr/include/stdio.h +memmenu.o: /usr/local/include/SDL/SDL_rwops.h memmenu.o: /usr/local/include/SDL/SDL_timer.h memmenu.o: /usr/local/include/SDL/SDL_audio.h memmenu.o: /usr/local/include/SDL/SDL_byteorder.h @@ -178,7 +182,11 @@ memmenu.o: /usr/local/include/SDL/SDL_mouse.h memmenu.o: /usr/local/include/SDL/SDL_video.h memmenu.o: /usr/local/include/SDL/SDL_mutex.h memmenu.o: /usr/local/include/SDL/SDL_quit.h -memmenu.o: /usr/local/include/SDL/SDL_version.h gfx.h gui.h +memmenu.o: /usr/local/include/SDL/SDL_version.h gfx.h gui.h util.h +util.o: /usr/include/stdio.h /usr/include/sys/cdefs.h +util.o: /usr/include/sys/_types.h /usr/include/machine/_types.h +util.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdarg.h +util.o: util.h /usr/include/stdlib.h exit.h exit.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h exit.o: /usr/include/sys/_types.h /usr/include/machine/_types.h exit.o: /usr/include/stdarg.h exit.h /usr/local/include/SDL/SDL.h diff --git a/src/gfx.c b/src/gfx.c index e7cecb8..ab7768c 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -50,9 +50,6 @@ static const char ident_fh[]=EZX81_FONT_H; #define FALSE 0 #endif -#define SCR_W 320 -#define SCR_H 200 - #define LOCK do \ { \ if (SDL_MUSTLOCK(surface)) \ @@ -171,8 +168,8 @@ void GFXInit(void) if (SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO)) Exit("Failed to init SDL: %s\n",SDL_GetError()); - if (!(surface=SDL_SetVideoMode(SCR_W*scale, - SCR_H*scale, + if (!(surface=SDL_SetVideoMode(GFX_WIDTH*scale, + GFX_HEIGHT*scale, 0, IConfig(CONF_FULLSCREEN) ? SDL_FULLSCREEN : 0))) @@ -182,6 +179,8 @@ void GFXInit(void) SDL_ShowCursor(SDL_DISABLE); SDL_WM_SetCaption("eZX81","eZX81"); + + atexit(SDL_Quit); } @@ -262,6 +261,18 @@ SDL_Event *GFXWaitKey(void) } +void GFXLock(void) +{ + LOCK; +} + + +void GFXUnlock(void) +{ + UNLOCK; +} + + void GFXPlot(int x, int y, Uint32 col) { LOCK; @@ -272,6 +283,12 @@ void GFXPlot(int x, int y, Uint32 col) } +void GFXFastPlot(int x, int y, Uint32 col) +{ + putpixel(x,y,col); +} + + void GFXRect(int x, int y, int w, int h, Uint32 col, int solid) { LOCK; @@ -334,11 +351,11 @@ void GFXPrint(int x, int y, Uint32 col, const char *format, ...) { for(sy=0;sy<8;sy++) { - if (y+sylen) + { + p[len]=0; + p[len-1]='.'; + p[len-2]='.'; + } +} - init=TRUE; - white=GFXRGB(255,255,255); - black=GFXRGB(0,0,0); - pale=GFXRGB(200,200,200); - red=GFXRGB(255,100,100); +static void Centre(const char *p, int y, Uint32 col) +{ + GFXPrint((GFX_WIDTH-strlen(p)*8)/2,y,col,"%s",p); } -static void *Malloc(size_t size) +static void Box(const char *title, int x, int y, int width, int height) { - void *p=malloc(size); + GFXRect(x+1,y+1, + width-2,height-2, + BLACK,TRUE); + + GFXRect(x+1,y+1, + width-2,11, + LOGREY,TRUE); - if (!p) - Exit("malloc failed for %lu bytes\n",(unsigned long)size); + GFXRect(x,y, + width,height, + GREY,FALSE); - return p; + Centre(title,y+2,GREEN); + GFXHLine(x,x+width-1,y+11,GREY); } -static void Centre(const char *p, int y, Uint32 col) +static int DoList(const char *title, int no, char * const list[], int *option) { - GFXPrint((SCR_W-strlen(p)*8)/2,y,col,"%s",p); + static const int max=GFX_HEIGHT/8-8; + SDL_Event *e; + int top; + int cur; + int done; + int f; + + if (no==0) + return -1; + + top=0; + cur=0; + + done=FALSE; + + while(!done) + { + Box(title,7,7,GFX_WIDTH-14,GFX_HEIGHT-14); + + if (option) + { + Centre("Cursors to move, RETURN to accept", + GFX_HEIGHT-44,WHITE); + Centre("SPACE toggles, I inverts all", + GFX_HEIGHT-36,WHITE); + Centre("S select all, C clear all", + GFX_HEIGHT-28,WHITE); + } + else + Centre("Cursors and RETURN to select",GFX_HEIGHT-28,WHITE); + + Centre("ESCAPE to cancel",GFX_HEIGHT-20,WHITE); + + for(f=0;fkey.keysym.sym) + { + case SDLK_RETURN: + done=TRUE; + break; + + case SDLK_SPACE: + if (option) + option[cur]=!option[cur]; + break; + + case SDLK_i: + if (option) + for(f=0;f0) + { + cur--; + + if (curtop+max-2) + top=cur-max+2; + } + break; + + default: + break; + } + } + + return cur; } /* ---------------------------------------- EXPORTED INTERFACES */ -void GUIMessage(const char *title, const char *format,...) +int GUIMessage(GUIBoxType type, const char *title, const char *format,...) { char buff[1025]; va_list va; @@ -109,8 +237,9 @@ void GUIMessage(const char *title, const char *format,...) int width; int height; int x,y; + int ret; - Init(); + ret=FALSE; va_start(va,format); vsprintf(buff,format,va); @@ -129,66 +258,96 @@ void GUIMessage(const char *title, const char *format,...) line=Malloc(sizeof *line * no); + width=16; + line[0]=strtok(buff,"\n"); - width=strlen(line[0]); + Trim(line[0],38); + + if (strlen(line[0])>width) + width=strlen(line[0]); for(f=1;fwidth) width=strlen(line[f]); } - width=(width*8)+16; - height=(no+3)*10; - - if (width>(SCR_W-10)) - width=SCR_W-10; + width=(width*8)+18; + height=(no+5)*10; - if (height>(SCR_H-10)) - height=SCR_H-10; + if (width>(GFX_WIDTH-10)) + width=GFX_WIDTH-10; - y=(SCR_H-height)/2; - x=(SCR_W-width)/2; + if (height>(GFX_HEIGHT-10)) + height=GFX_HEIGHT-10; - GFXRect(x-1,y-1,width+2,height+2,white,FALSE); - GFXRect(x,y,width,height,black,TRUE); + y=(GFX_HEIGHT-height)/2; + x=(GFX_WIDTH-width)/2; - Centre(title,y+2,white); - GFXHLine(x+2,x+width-4,y+10,white); + Box(title,x,y,width,height); for(f=0;fkey.keysym.sym==SDLK_y) + { + ret=TRUE; + break; + } + else if (e->key.keysym.sym==SDLK_n) + { + ret=FALSE; + break; + } + } + } + else + GFXWaitKey(); + free(line); + + return ret; } const char *GUIInputString(const char *prompt, const char *orig) { - static const int y_pos=SCR_H-8; + static const int y_pos=GFX_HEIGHT-8; static char buff[41]; size_t len; int done=FALSE; + unsigned char c; SDL_Event *e; - Init(); - buff[0]=0; strncat(buff,orig,40); len=strlen(buff); + SDL_EnableUNICODE(1); + while(!done) { - GFXRect(0,y_pos,SCR_W,8,black,TRUE); - GFXPrint(0,y_pos,white,"%s %s%c",prompt,buff,FONT_CURSOR); + GFXRect(0,y_pos,GFX_WIDTH,8,BLACK,TRUE); + GFXPrint(0,y_pos,WHITE,"%s %s%c",prompt,buff,FONT_CURSOR); GFXEndFrame(FALSE); e=GFXWaitKey(); @@ -213,17 +372,53 @@ const char *GUIInputString(const char *prompt, const char *orig) break; default: - if (len<40 && isprint(e->key.keysym.sym)) + c=(unsigned char)e->key.keysym.unicode; + + if (len<40 && isprint(c)) { - buff[len++]=(char)e->key.keysym.sym; + buff[len++]=c; buff[len]=0; } break; } } + SDL_EnableUNICODE(0); + return buff; } +int GUIListSelect(const char *title, int no, char * const list[]) +{ + return DoList(title,no,list,NULL); +} + + +int GUIListOption(const char *title, int no, char * const list[], int option[]) +{ + int *o; + int sel; + int f; + + if (no==0) + return FALSE; + + o=Malloc(no * sizeof *o); + + for(f=0;f #include +#include #include "SDL.h" @@ -74,10 +75,11 @@ int main(int argc, char *argv[]) z80=Z80Init(ZX81WriteMem, ZX81ReadMem, + ZX81WriteWord, + ZX81ReadWord, ZX81WritePort, ZX81ReadPort, - ZX81ReadForDisassem, - NULL); + ZX81ReadForDisassem); GFXInit(); @@ -89,8 +91,16 @@ int main(int argc, char *argv[]) quit=FALSE; + /* Check for initial memory menu usage + TODO: Proper switch handling + */ + if (argc>1 && strcmp(argv[1],"-m")==0) + quit=MemoryMenu(z80); + while(!quit) { + const char *brk; + Z80SingleStep(z80); if (trace) @@ -99,22 +109,67 @@ int main(int argc, char *argv[]) GFXEndFrame(FALSE); } + if ((brk=Break())) + { + GUIMessage(eMessageBox,"BREAKPOINT","%s",brk); + quit=MemoryMenu(z80); + } + while((e=GFXGetKey())) { switch (e->key.keysym.sym) { + case SDLK_F1: + if (e->key.state==SDL_PRESSED) + GUIMessage(eMessageBox, + "HELP", + "ESC - Quit \n" + "F1 - Help \n" + "F2 - About \n" + "F3 - View ZX81 keyboad \n" + "F10 - Close all open tape files \n" + "F11 - Memory Menu \n" + "F12 - Toggle onscreen trace "); + break; + + case SDLK_F2: + if (e->key.state==SDL_PRESSED) + GUIMessage(eMessageBox, + "eZX81 - ZX81 Emulator", + "(c) 2004 Ian Cowburn\n" + " \n" + "This software comes with ABSOLUTELY \n" + "NO WARRANTY, and you are free to \n" + "to redistribute it under certain \n" + "conditions. See the supplied GNU \n" + "General Public License in LICENSE \n" + "for details. \n" + " \n" + "If you did not recieve a license, \n" + "vist www.gnu.org or wrote to: \n" + " \n" + "Free Software Foundation, Inc., \n" + "59 Temple Place, Suite 330, \n" + "Boston, MA 02111-1307 USA "); + break; + + case SDLK_F3: + if (e->key.state==SDL_PRESSED) + GUIMessage(eMessageBox,"TODO","Sorry, not done yet"); + break; + case SDLK_ESCAPE: - if (e->key.state==SDL_RELEASED) - quit=TRUE; + if (e->key.state==SDL_PRESSED) + quit=GUIMessage(eYesNoBox,"QUIT","Sure?"); break; case SDLK_F11: - if (e->key.state==SDL_RELEASED) - MemoryMenu(z80); + if (e->key.state==SDL_PRESSED) + quit=MemoryMenu(z80); break; case SDLK_F12: - if (e->key.state==SDL_RELEASED) + if (e->key.state==SDL_PRESSED) trace=!trace; break; diff --git a/src/memmenu.c b/src/memmenu.c index 3bb800c..95429f9 100644 --- a/src/memmenu.c +++ b/src/memmenu.c @@ -26,6 +26,7 @@ static const char ident[]="$Id$"; #include +#include #include #include @@ -33,33 +34,112 @@ static const char ident[]="$Id$"; #include "zx81.h" #include "gfx.h" #include "gui.h" +#include "util.h" #include static const char ident_h[]=EZX81_MEMMENU_H; #ifndef TRUE -#define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE -#define FALSE 0 +#define FALSE 0 #endif -#define WHITE GFXRGB(255,255,255) -#define BLACK GFXRGB(0,0,0) -#define RED GFXRGB(255,100,100) -#define GREEN GFXRGB(100,255,100) -#define BLUE GFXRGB(100,100,255) +#define WHITE GFXRGB(255,255,255) +#define BLACK GFXRGB(0,0,0) +#define RED GFXRGB(255,100,100) +#define GREEN GFXRGB(100,255,100) +#define BLUE GFXRGB(100,100,255) -#define MENU +#define TRACE "trace" +#define TRACEMEM_WIN 6 + + +/* ---------------------------------------- TYPES +*/ +typedef struct +{ + int no; + int *active; + char **expr; +} Breakpoint; + + +typedef struct +{ + Z80Word addr; + Z80Word val; +} MemTrace; + + +typedef struct +{ + Z80State s; + MemTrace hl[TRACEMEM_WIN]; + MemTrace de[TRACEMEM_WIN]; + MemTrace sp[TRACEMEM_WIN]; +} Trace; + + +/* ---------------------------------------- STATIC DATA +*/ +static FILE *trace=NULL; +static Breakpoint bpoint={0,NULL,NULL}; +static const char *brk=NULL; +static int lodged=FALSE; + + +/* ---------------------------------------- PROTOS +*/ +static int Instruction(Z80 *z80, Z80Val data); /* ---------------------------------------- PRIVATE FUNCTIONS */ +static int BreaksActive(void) +{ + int f; + int ret=FALSE; + + for(f=0;fPC,s->AF>>8,FlagString(s->AF&0xff)); + y+=8; + GFXPrintPaper(0,y,col,BLACK, + "BC=%4.4x DE=%4.4x HL=%4.4x", + s->BC,s->DE,s->HL); + y+=8; + GFXPrintPaper(0,y,col,BLACK, + "IX=%4.4x IY=%4.4x SP=%4.4x", + s->IX,s->IY,s->SP); + y+=8; + GFXPrintPaper(0,y,col,BLACK, + "AF'=%4.4x BC'=%4.4x DE'=%4.4x HL'=%4.4x", + s->AF_,s->BC_,s->DE_,s->HL_); + y+=8; + GFXPrintPaper(0,y,col,BLACK, + "I=%2.2x IM=%2.2x R=%2.2x", + s->I,s->IM,s->R); + y+=8; + GFXPrintPaper(0,y,col,BLACK, + "IFF1=%2.2x IFF2=%2.2x", + s->IFF1,s->IFF2); - if (StrEq(p,"AF")) - return s.AF; - else if (StrEq(p,"BC")) - return s.BC; - else if (StrEq(p,"DE")) - return s.DE; - else if (StrEq(p,"HL")) - return s.HL; - else if (StrEq(p,"IX")) - return s.IX; - else if (StrEq(p,"IY")) - return s.IY; - else if (StrEq(p,"SP")) - return s.SP; - else if (StrEq(p,"PC")) - return s.PC; - - return (Z80Word)strtoul(p,NULL,0); + return y+8; } -static int EnterAddress(Z80 *z80, Z80Word *w) +static int EnterAddress(const char *prompt, Z80 *z80, Z80Word *w) { - unsigned long ul; const char *p; + char *error; + long l; - p=GUIInputString("Address?",""); + p=GUIInputString(prompt ? prompt : "Address?",""); if (*p) { - ul=Address(z80,p); - - if (ul>0xffff) + if (!Z80Expression(z80,p,&l,&error)) { - GUIMessage("ERROR","Bad address"); + GUIMessage(eMessageBox, + "ERROR","%s",error ? error:"Invalid expression"); + + free(error); } else { - *w=(Z80Word)ul; + *w=(Z80Word)l; return TRUE; } } @@ -173,6 +254,17 @@ static int EnterAddress(Z80 *z80, Z80Word *w) } +static void EnterLong(const char *prompt, long *l) +{ + const char *p; + + p=GUIInputString(prompt ? prompt : "Value?",""); + + if (*p) + *l=strtol(p,NULL,0); +} + + static void DoDisassem(Z80 *z80, const Z80State *s) { static int hexmode=FALSE; @@ -188,31 +280,45 @@ static void DoDisassem(Z80 *z80, const Z80State *s) GFXClear(BLACK); - Centre("Press F1 for help",0,RED); + Centre("DISASSEMBLY",0,WHITE); + Centre("Press F1 for help",9,RED); curr=pc; - for(f=0;f<21;f++) + for(f=0;fkey.keysym.sym) + { + case SDLK_F1: + GUIMessage + (eMessageBox,"PLAYBACK HELP","%s", + "ESC - Exit \n" + "Enter - Step number \n" + "P - Search for PC \n" + "M - Toggle CPU state/memory \n" + "Up - Prev step \n" + "Down - Next step \n" + "Page Up - Back 50 steps \n" + "Page Down - Forward 50 steps \n" + "Left - Back 1000 steps \n" + "Right - Forward 1000 steps \n \n" + "NOTE: Disassembly is as memory is NOW"); + break; + + case SDLK_ESCAPE: + quit=TRUE; + break; + + case SDLK_RETURN: + case SDLK_KP_ENTER: + EnterLong("Step number?",&pos); + pos--; + break; + + case SDLK_p: + if (EnterAddress("PC to search for?",z80,&pc)) + { + while((rd=fread(&t,sizeof t,1,fp))==1) + { + pos++; + if (t.s.PC==pc) + break; + } + + if (rd!=1) + { + GUIMessage(eMessageBox,"NOTICE","Address not found"); + pos=prev_pos; + } + } + break; + + case SDLK_m: + showmem=!showmem; + break; + + case SDLK_UP: + pos--; + break; + + case SDLK_DOWN: + pos++; + break; + + case SDLK_PAGEUP: + pos-=50; + break; + + case SDLK_PAGEDOWN: + pos+=50; + break; + + case SDLK_LEFT: + pos-=1000; + break; + + case SDLK_RIGHT: + pos+=1000; + break; + + default: + break; + } + + /* Check position before next loop + */ + if (pos<0) + pos=0; + + if (pos>=max_pos) + pos=max_pos-1; + } + + fclose(fp); +} + + +static void DoAddBreakpoint(Z80 *z80) +{ + const char *expr; + char *error; + long l; + + expr=GUIInputString("Expression?",""); + + if (!*expr) + return; + + if (!Z80Expression(z80,expr,&l,&error)) + { + if (error) + { + GUIMessage(eMessageBox,"INVALID EXPRESSION","%s",error); + free(error); + } + else + { + GUIMessage(eMessageBox,"ERROR","Expression is invalid"); + free(error); + } + } + else + { + bpoint.no++; + bpoint.expr=Realloc(bpoint.expr,bpoint.no * sizeof(*bpoint.expr)); + bpoint.active=Realloc(bpoint.active,bpoint.no * sizeof(*bpoint.active)); + + bpoint.expr[bpoint.no-1]=StrCopy(expr); + bpoint.active[bpoint.no-1]=TRUE; + + SetCallback(z80); + } +} + + +static void DoActiveBreakpoint(Z80 *z80) +{ + if (bpoint.no==0) + { + GUIMessage(eMessageBox,"NOTICE","No breakpoints to set"); + return; + } + + GFXClear(BLACK); + + GUIListOption("SELECT ACTIVE BREAKPOINTS", + bpoint.no,bpoint.expr,bpoint.active); +} + + +static void DoRemoveBreakpoint(Z80 *z80) +{ + int sel; + + if (bpoint.no==0) + { + GUIMessage(eMessageBox,"NOTICE","No breakpoints to delete"); + return; + } + + GFXClear(BLACK); + + sel=GUIListSelect("BREAKPOINT TO DELETE",bpoint.no,bpoint.expr); + + while (sel!=-1) + { + int f; + + free(bpoint.expr[sel]); + + for(f=sel;fkey.state!=SDL_PRESSED) + e=NULL; + } + else + e=GFXWaitKey(); + + if (e) + { + switch(e->key.keysym.sym) + { + case SDLK_F1: + GUIMessage + (eMessageBox,"PLAYBACK HELP","%s", + "ESC - Exit \n" + "ENTER - Single step processor \n" + "R - Run till break or stop \n" + "SPACE - Stop running \n" + "M - Toggle CPU state/memory \n" + "5 - Add a new breakpoint \n" + "6 - Set active breakpoints \n" + "7 - Remove a breakpoint \n" + "8 - Clear all breakpoints "); + break; + + case SDLK_RETURN: + case SDLK_KP_ENTER: + step=TRUE; + break; + + case SDLK_ESCAPE: + quit=TRUE; + break; + + case SDLK_r: + running=TRUE; + break; + + case SDLK_SPACE: + running=FALSE; + break; + + case SDLK_m: + showmem=!showmem; + break; + + case SDLK_5: + DoAddBreakpoint(z80); + break; + + case SDLK_6: + DoActiveBreakpoint(z80); + break; + + case SDLK_7: + DoRemoveBreakpoint(z80); + break; + + case SDLK_8: + DoClearBreakpoint(z80); + break; + + default: + break; + } + } + + if (running || step) + Z80SingleStep(z80); + + if (running && (brk=Break())) + { + GUIMessage(eMessageBox,"BREAKPOINT","%s",brk); + running=FALSE; + } + } + + ZX81EnableScreen(TRUE); +} + + /* ---------------------------------------- EXPORTED INTERFACES */ -void MemoryMenu(Z80 *z80) +int MemoryMenu(Z80 *z80) { SDL_Event *e; + int done=FALSE; int quit=FALSE; Z80State s; + int y; Z80GetState(z80,&s); GFXKeyRepeat(TRUE); - while(!quit) + while(!done) { DisplayMenu(); - DisplayState(z80); GFXEndFrame(FALSE); e=GFXWaitKey(); @@ -322,17 +1025,78 @@ void MemoryMenu(Z80 *z80) DoDisassem(z80,&s); break; - case SDLK_ESCAPE: case SDLK_2: + DoDisassemFile(z80,&s); + break; + + case SDLK_3: + if (!trace) + EnableTrace(z80,&s); + else + DisableTrace(z80); + break; + + case SDLK_4: + DisableTrace(z80); + PlaybackTrace(z80); + break; + + case SDLK_5: + DoAddBreakpoint(z80); + break; + + case SDLK_6: + DoActiveBreakpoint(z80); + break; + + case SDLK_7: + DoRemoveBreakpoint(z80); + break; + + case SDLK_8: + DoClearBreakpoint(z80); + break; + + case SDLK_9: + DoMonitor(z80); + break; + + case SDLK_r: + if (GUIMessage(eYesNoBox,"RESET","Sure?")) + { + Z80Reset(z80); + ZX81Reset(z80); + } + break; + + case SDLK_x: + done=TRUE; quit=TRUE; break; + case SDLK_s: + GFXClear(BLACK); + Centre("CURRENT STATE",0,WHITE); + Centre("Press a key",9,RED); + y=DisplayZ80State(&s,20,WHITE); + GFXPrint(0,y,GREEN,"%s",ZX81Info(z80)); + GFXEndFrame(FALSE); + GFXWaitKey(); + break; + + case SDLK_ESCAPE: + done=TRUE; + break; + default: break; } } GFXKeyRepeat(FALSE); + + GFXClear(BLACK); + return quit; } @@ -342,31 +1106,20 @@ void DisplayState(Z80 *z80) int y; Z80GetState(z80,&s); + y=DisplayZ80State(&s,GFX_HEIGHT/2,RED); + GFXPrintPaper(0,y,GREEN,BLACK,"%s",ZX81Info(z80)); +} - y=136; - - GFXPrintPaper(0,y,RED,BLACK,"PC=%4.4x A=%2.2x F=%s", - s.PC,s.AF>>8,FlagString(s.AF&0xff)); - y+=8; - - GFXPrintPaper(0,y,RED,BLACK,"BC=%4.4x DE=%4.4x HL=%4.4x",s.BC,s.DE,s.HL); - y+=8; - - GFXPrintPaper(0,y,RED,BLACK,"IX=%4.4x IY=%4.4x SP=%4.4x",s.IX,s.IY,s.SP); - y+=8; - GFXPrintPaper(0,y,RED,BLACK,"I=%2.2x IM=%2.2x R=%2.2x",s.I,s.IM,s.R); - y+=8; +const char *Break(void) +{ + const char *ret; - GFXPrintPaper(0,y,RED,BLACK,"IFF1=%2.2x IFF2=%2.2x",s.IFF1,s.IFF2); - y+=8; + ret=brk; + brk=NULL; - y+=8; - GFXPrintPaper(0,y,RED,BLACK,"%s\n",ZX81Info(z80)); - y+=8; + return ret; } - - /* END OF FILE */ diff --git a/src/memmenu.h b/src/memmenu.h index bacbef9..1caecb5 100644 --- a/src/memmenu.h +++ b/src/memmenu.h @@ -30,14 +30,19 @@ #include "z80.h" -/* Memory menu +/* Memory menu. Returns TRUE if exit (from program) selected. */ -void MemoryMenu(Z80 *z80); +int MemoryMenu(Z80 *z80); -/* Display the state of the ZX81 at the bottom of the screen +/* Display the state of the SPEC at the bottom of the screen */ -void DisplayState(Z80 *z80); +void DisplayState(Z80 *z80); + + +/* Non-NULL (the breakpoint hit) if a breakpoint has been hit +*/ +const char *Break(void); #endif diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..566255d --- /dev/null +++ b/src/util.c @@ -0,0 +1,131 @@ +/* + + espec - Sinclair Spectrum emulator + + Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk) + + 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 + + ------------------------------------------------------------------------- + + Usual library wrappers and utils + +*/ +static const char ident[]="$Id$"; + +#include +#include +#include + +#include "util.h" +#include "exit.h" + +static const char ident_h[]=ESPEC_UTIL_H; + + +/* ---------------------------------------- MACROS +*/ +#define DIRSEP '/' + +/* ---------------------------------------- INTERFACES +*/ +void *Malloc(size_t size) +{ + void *new=malloc(size); + + if (!new) + Exit("malloc failed for %lu bytes\n",(unsigned long)size); + + return new; +} + + +void *Realloc(void *p, size_t size) +{ + void *new=realloc(p,size); + + if (!new) + Exit("realloc failed for %lu bytes\n",(unsigned long)size); + + return new; +} + + +char *StrCopy(const char *source) +{ + return strcpy(Malloc(strlen(source)+1),source); +} + + +const char *Basename(const char *path) +{ + const char *p=path+strlen(path); + + while(p>path && *p!=DIRSEP) + p--; + + if (p>path) + p++; + + return p; +} + + +const char *Dirname(const char *path) +{ + static char dir[FILENAME_MAX]; + char *p; + + strcpy(dir,path); + + p=dir+strlen(dir); + + while(p>dir && *p!=DIRSEP) + p--; + + if (p>path) + { + p++; + *p=0; + } + else + { + strcpy(dir,"."); + } + + return dir; +} + + +void Debug(const char *format, ...) +{ + static FILE *fp=NULL; + va_list ap; + + if (!fp) + { + fp=fopen("debug.txt","w"); + setbuf(fp,NULL); + } + + if (!fp) + return; + + va_start(ap,format); + vfprintf(fp,format,ap); + va_end(ap); +} + +/* END OF FILE */ diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..922f641 --- /dev/null +++ b/src/util.h @@ -0,0 +1,73 @@ +/* + + espec - Sinclair Spectrum emulator + + Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk) + + 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 + + ------------------------------------------------------------------------- + + Usual library wrappers and utils + +*/ + +#ifndef ESPEC_UTIL_H +#define ESPEC_UTIL_H "$Id$" + +#include + +/* ---------------------------------------- INTERFACES +*/ + +/* Returns result from malloc(size), calling Exit() if it fails. +*/ +void *Malloc(size_t size); + + +/* Returns result from realloc(p,size), calling Exit() if it fails. +*/ +void *Realloc(void *p, size_t size); + + +/* Copies a string. The result must be freed. +*/ +char *StrCopy(const char *source); + + +/* Returns the filename portion of path. Note returned pointer is pointing + inside of path. +*/ +const char *Basename(const char *path); + + +/* Returns the directory portion of path. Note returned pointer is internal + static storage. If there are no directory seperators in path, "." is + returned. +*/ +const char *Dirname(const char *path); + + +/* Writes the passed text to debug.txt. Note this is interface is not + able to be switched on/off, so debug is only used in a transient way + (once the bug is fixed, calls to this should be removed). +*/ +void Debug(const char *format,...); + + +#endif + + +/* END OF FILE */ diff --git a/src/zx81.c b/src/zx81.c index 603bbd9..a7299e4 100644 --- a/src/zx81.c +++ b/src/zx81.c @@ -51,21 +51,21 @@ static const int ROMLEN=0x2000; static const int ROM_SAVE=0x2fc; static const int ROM_LOAD=0x347; -/* No of cycles in each 64us HSYNC (hopefully) +/* No of T-states in each 64us HSYNC (hopefully) */ -static const int HSYNC_PERIOD=321; +static const Z80Val HSYNC_PERIOD=321; /* The ZX81 screen */ -static const int SCR_W=256; -static const int SCR_H=192; -static const int TXT_W=32; -static const int TXT_H=24; +static int scr_enable=TRUE; -/* These assume a 320x200 screen -*/ -static const int OFF_X=(320-256)/2; -static const int OFF_Y=(200-192)/2; +#define SCR_W 256 +#define SCR_H 192 +#define TXT_W 32 +#define TXT_H 24 + +#define OFF_X (GFX_WIDTH-SCR_W)/2 +#define OFF_Y (GFX_HEIGHT-SCR_H)/2 static Z80Byte mem[0x10000]; @@ -249,7 +249,7 @@ static void LoadTape(Z80State *state) if (strlen(p)==0) { - GUIMessage("ERROR","Can't load empty filename"); + GUIMessage(eMessageBox,"ERROR","Can't load empty filename"); return; } @@ -260,7 +260,7 @@ static void LoadTape(Z80State *state) if (!(fp=fopen(path,"rb"))) { - GUIMessage("ERROR","Can't load file:\n%s",path); + GUIMessage(eMessageBox,"ERROR","Can't load file:\n%s",path); return; } @@ -288,7 +288,7 @@ static void SaveTape(Z80State *state) if (strlen(p)==0) { - GUIMessage("ERROR","Can't save empty filename"); + GUIMessage(eMessageBox,"ERROR","Can't save empty filename"); return; } @@ -299,7 +299,7 @@ static void SaveTape(Z80State *state) if (!(fp=fopen(path,"wb"))) { - GUIMessage("ERROR","Can't write file:\n%s",path); + GUIMessage(eMessageBox,"ERROR","Can't write file:\n%s",path); return; } @@ -345,6 +345,9 @@ static void ULA_Video_Shifter(Z80 *z80, Z80Byte val) int inv; int b; + if (!scr_enable) + return; + Z80GetState(z80,&state); /* Extra check due to out dodgy ULA emulation @@ -396,12 +399,12 @@ static int CheckTimers(Z80 *z80, Z80Val val) { if (val>HSYNC_PERIOD) { - Z80ResetCycles(z80,0); + Z80ResetCycles(z80,val-HSYNC_PERIOD); - if (nmigen) + if (nmigen && hsync) { - Z80NMI(z80,0xff); - printf("NMIGEN\n"); + Z80NMI(z80); + /*printf("NMIGEN\n");*/ } else if (hsync) { @@ -429,22 +432,24 @@ void ZX81Init(Z80 *z80) if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb"))) { - GUIMessage("ERROR","Failed to open ZX81 ROM\n%s",SConfig(CONF_ROMFILE)); + GUIMessage(eMessageBox, + "ERROR","Failed to open ZX81 ROM\n%s",SConfig(CONF_ROMFILE)); Exit(""); } if (fread(mem,1,ROMLEN,fp)!=ROMLEN) { fclose(fp); - GUIMessage("ERROR","ROM file must be %d bytes long\n",ROMLEN); + GUIMessage(eMessageBox, + "ERROR","ROM file must be %d bytes long\n",ROMLEN); Exit(""); } /* Patch the ROM */ RomPatch(); - Z80LodgeCallback(z80,Z80_EDHook,EDCallback); - Z80LodgeCallback(z80,Z80_Fetch,CheckTimers); + Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); + Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); /* Mirror the ROM */ @@ -544,6 +549,16 @@ Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) } +Z80Word ZX81ReadWord(Z80 *z80, Z80Word addr) +{ + Z80Word l,h; + + l=ZX81ReadMem(z80,addr); + h=ZX81ReadMem(z80,addr+1); + return (h<<8)|l; +} + + void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) { addr=addr&0x7fff; @@ -553,6 +568,18 @@ void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) } +void ZX81WriteWord(Z80 *z80, Z80Word addr, Z80Word val) +{ + if (addr>=RAMBOT && addr<=RAMTOP) + mem[addr]=val&0xff; + + addr++; + + if (addr>=RAMBOT && addr<=RAMTOP) + mem[addr]=val>>8; +} + + Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) { Z80Byte b=0; @@ -597,6 +624,7 @@ Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) */ if (!nmigen && hsync) { + printf("HSYNC OFF\n"); hsync=FALSE; GFXEndFrame(TRUE); @@ -637,14 +665,17 @@ void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) switch(port&0xff) { case 0xfd: /* NMI generator OFF */ + printf("NMIGEN OFF\n"); nmigen=FALSE; break; case 0xfe: /* NMI generator ON */ + printf("NMIGEN ON\n"); nmigen=TRUE; break; case 0xff: /* HSYNC generator ON */ + printf("HSYNC ON\n"); hsync=TRUE; Z80ResetCycles(z80,0); break; @@ -662,12 +693,29 @@ const char *ZX81Info(Z80 *z80) { static char buff[80]; - sprintf(buff,"NMIGEN: %s HSYNC: %s", + sprintf(buff,"NMI: %s HS: %s ULA: (%d,%d,%d,%d)", nmigen ? "ON":"OFF", - hsync ? "ON":"OFF"); + hsync ? "ON":"OFF", + ULA.x,ULA.y,ULA.c,ULA.release); return buff; } +void ZX81EnableScreen(int enable) +{ + scr_enable=enable; +} + + +void ZX81Reset(Z80 *z80) +{ + scr_enable=TRUE; + nmigen=FALSE; + hsync=FALSE; + + GFXStartFrame(); +} + + /* END OF FILE */ diff --git a/src/zx81.h b/src/zx81.h index 855c4a5..f308e8b 100644 --- a/src/zx81.h +++ b/src/zx81.h @@ -43,6 +43,8 @@ void ZX81KeyEvent(SDL_Event *e); */ Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr); void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val); +Z80Word ZX81ReadWord(Z80 *z80, Z80Word addr); +void ZX81WriteWord(Z80 *z80, Z80Word addr, Z80Word val); Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port); void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val); Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr); @@ -50,6 +52,8 @@ Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr); /* Interfaces for memory menu */ const char *ZX81Info(Z80 *z80); +void ZX81EnableScreen(int enable); +void ZX81Reset(Z80 *z80); #endif -- cgit v1.2.3