summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gfx.c15
-rw-r--r--src/gfx.h13
-rw-r--r--src/gui.c223
-rw-r--r--src/gui.h20
-rw-r--r--src/main.c13
-rw-r--r--src/memmenu.c300
-rw-r--r--src/memmenu.h11
-rw-r--r--src/spec.c56
-rw-r--r--src/spec.h4
-rw-r--r--src/util.c17
-rw-r--r--src/util.h5
11 files changed, 527 insertions, 150 deletions
diff --git a/src/gfx.c b/src/gfx.c
index a2d1623..7906e84 100644
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -50,9 +50,6 @@ static const char ident_fh[]=ESPEC_FONT_H;
#define FALSE 0
#endif
-#define SCR_W 320
-#define SCR_H 300
-
#define LOCK do \
{ \
if (SDL_MUSTLOCK(surface)) \
@@ -179,8 +176,8 @@ void GFXInit(void)
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)))
@@ -362,11 +359,11 @@ void GFXPrint(int x, int y, Uint32 col, const char *format, ...)
{
for(sy=0;sy<8;sy++)
{
- if (y+sy<SCR_H && x<SCR_W)
+ if (y+sy<GFX_HEIGHT && x<GFX_WIDTH)
{
for(sx=0;sx<8;sx++)
{
- if (font[(int)*p][sx+sy*8] && x+sx<SCR_W)
+ if (font[(int)*p][sx+sy*8] && x+sx<GFX_WIDTH)
putpixel(x+sx,y+sy,col);
}
}
@@ -400,11 +397,11 @@ void GFXPrintPaper(int x, int y, Uint32 col, Uint32 paper,
{
for(sy=0;sy<8;sy++)
{
- if (y+sy<SCR_H && x<SCR_W)
+ if (y+sy<GFX_HEIGHT && x<GFX_WIDTH)
{
for(sx=0;sx<8;sx++)
{
- if (font[(int)*p][sx+sy*8] && x+sx<SCR_W)
+ if (font[(int)*p][sx+sy*8] && x+sx<GFX_WIDTH)
putpixel(x+sx,y+sy,col);
else
putpixel(x+sx,y+sy,paper);
diff --git a/src/gfx.h b/src/gfx.h
index d3f1ec3..9b35868 100644
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -41,6 +41,11 @@
#define FONT_CURSOR '\007'
#define FONT_COPYRIGHT '\010'
+/* The size of the display
+*/
+#define GFX_WIDTH 320
+#define GFX_HEIGHT 300
+
/* ---------------------------------------- INTERFACES
*/
@@ -50,6 +55,12 @@
void GFXInit(void);
+/* Size of the screen
+*/
+int GFXHeight(void);
+int GFXWidth(void);
+
+
/* Get the SDL_Surface for the screen
*/
SDL_Surface *GFXGetSurface(void);
@@ -87,7 +98,7 @@ void GFXKeyRepeat(int repeat);
SDL_Event *GFXGetKey(void);
-/* Wait for a keypress (key up event)
+/* Wait for a keypress. Note that key up events are returned.
*/
SDL_Event *GFXWaitKey(void);
diff --git a/src/gui.c b/src/gui.c
index 5072be1..cfd109e 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -34,6 +34,7 @@ static const char ident[]="$Id$";
#include "gui.h"
#include "gfx.h"
#include "exit.h"
+#include "util.h"
static const char ident_h[]=ESPEC_GUI_H;
@@ -48,10 +49,12 @@ static const char ident_h[]=ESPEC_GUI_H;
#define FALSE 0
#endif
-/* Must match gfx.c
-*/
-#define SCR_W 320
-#define SCR_H 200
+#define WHITE GFXRGB(255,255,255)
+#define BLACK GFXRGB(0,0,0)
+#define RED GFXRGB(255,100,100)
+#define GREY GFXRGB(160,160,160)
+#define LOGREY GFXRGB(100,100,100)
+#define GREEN GFXRGB(100,255,100)
/* ---------------------------------------- STATICS
*/
@@ -59,26 +62,45 @@ static const char ident_h[]=ESPEC_GUI_H;
/* ---------------------------------------- PRIVATE FUNCTIONS
*/
-static void *Malloc(size_t size)
+static void Trim(char *p,size_t len)
{
- void *p=malloc(size);
+ if (strlen(p)>len)
+ {
+ p[len]=0;
+ p[len-1]='.';
+ p[len-2]='.';
+ }
+}
- if (!p)
- Exit("malloc failed for %lu bytes\n",(unsigned long)size);
- return p;
+static void Centre(const char *p, int y, Uint32 col)
+{
+ GFXPrint((GFX_WIDTH-strlen(p)*8)/2,y,col,"%s",p);
}
-static void Centre(const char *p, int y, int r, int g, int b)
+static void Box(const char *title, int x, int y, int width, int height)
{
- GFXPrint((SCR_W-strlen(p)*8)/2,y,GFXRGB(r,g,b),"%s",p);
+ GFXRect(x+1,y+1,
+ width-2,height-2,
+ BLACK,TRUE);
+
+ GFXRect(x+1,y+1,
+ width-2,11,
+ LOGREY,TRUE);
+
+ GFXRect(x,y,
+ width,height,
+ GREY,FALSE);
+
+ Centre(title,y+2,GREEN);
+ GFXHLine(x,x+width-1,y+11,GREY);
}
/* ---------------------------------------- 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;
@@ -89,6 +111,9 @@ void GUIMessage(const char *title, const char *format,...)
int width;
int height;
int x,y;
+ int ret;
+
+ ret=FALSE;
va_start(va,format);
vsprintf(buff,format,va);
@@ -107,69 +132,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;f<no;f++)
{
line[f]=strtok(NULL,"\n");
+ Trim(line[f],38);
if (strlen(line[f])>width)
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+3)*12;
- 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,
- GFXRGB(255,255,255),FALSE);
-
- GFXRect(x,y,
- width,height,
- GFXRGB(0,0,0),TRUE);
+ y=(GFX_HEIGHT-height)/2;
+ x=(GFX_WIDTH-width)/2;
- Centre(title,y+2,255,255,255);
- GFXHLine(x+2,x+width-4,y+10,GFXRGB(255,255,255));
+ Box(title,x,y,width,height);
for(f=0;f<no;f++)
- Centre(line[f],y+5+10*(f+1),200,200,200);
+ Centre(line[f],y+5+10*(f+1),WHITE);
- Centre("Press a key",y+height-10,255,0,0);
+ if (type==eMessageBox)
+ Centre("Press a key",y+height-12,RED);
+ else
+ Centre("Press Y/N",y+height-12,RED);
GFXEndFrame(FALSE);
- GFXWaitKey();
+ if (type==eYesNoBox)
+ {
+ SDL_Event *e;
+
+ while(TRUE)
+ {
+ e=GFXWaitKey();
+
+ if (e->key.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;
buff[0]=0;
strncat(buff,orig,40);
len=strlen(buff);
+ SDL_EnableUNICODE(1);
+
while(!done)
{
- GFXRect(0,y_pos,SCR_W,8,GFXRGB(0,0,0),TRUE);
- GFXPrint(0,y_pos,GFXRGB(255,255,255),"%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();
@@ -194,19 +246,112 @@ 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[])
+{
+ 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);
+
+ Centre("Cursors and RETURN to select",GFX_HEIGHT-40,WHITE);
+ Centre("ESCAPE to cancel",GFX_HEIGHT-32,WHITE);
+
+ for(f=0;f<max;f++)
+ {
+ if (f+top<no)
+ {
+ Uint32 pen,paper;
+
+ if (f+top==cur)
+ {
+ pen=WHITE;
+ paper=RED;
+ }
+ else
+ {
+ pen=GREY;
+ paper=BLACK;
+ }
+
+ GFXPrintPaper(16,20+f*8,pen,paper,"%-36.36s",list[f+top]);
+ }
+ }
+
+ GFXEndFrame(FALSE);
+
+ e=GFXWaitKey();
+
+ switch(e->key.keysym.sym)
+ {
+ case SDLK_RETURN:
+ done=TRUE;
+ break;
+
+ case SDLK_ESCAPE:
+ cur=-1;
+ done=TRUE;
+ break;
+
+ case SDLK_UP:
+ if (cur>0)
+ {
+ cur--;
+
+ if (cur<top)
+ top=cur;
+ }
+ break;
+
+ case SDLK_DOWN:
+ if (cur<no-1)
+ {
+ cur++;
+
+ if (cur>top+max-2)
+ top=cur-max+2;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return cur;
+}
+
+
int GUIFileSelect(const char *prompt, int load,
const char *start_dir, char path[])
{
diff --git a/src/gui.h b/src/gui.h
index 953aac9..e1ad43a 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -31,10 +31,20 @@
/* ---------------------------------------- INTERFACES
*/
+/* Message types
+*/
+typedef enum {eMessageBox, eYesNoBox} GUIBoxType;
+
/* Display a simple message box. A message of longer than 1024 bytes causes
- undefined behaviour. Newlines cause a line break.
+ undefined behaviour. Newlines cause a line break. If a line is over 38
+ characters then it will be truncated.
+
+ If type is eYesNoBox then TRUE/FALSE is returned depending on whether
+ yes/no was selected.
*/
-void GUIMessage(const char *title, const char *format,...);
+int GUIMessage(GUIBoxType type,
+ const char *title,
+ const char *format,...);
/* Enter a string, max 40 characters
@@ -42,6 +52,12 @@ void GUIMessage(const char *title, const char *format,...);
const char *GUIInputString(const char *prompt, const char *orig);
+/* Selects an entry from a list. Returns the index selected, or
+ -1 if cancelled.
+*/
+int GUIListSelect(const char *title, int no, char * const list[]);
+
+
/* Select a file from the given directory.
If load is TRUE then a new name cannot be entered.
diff --git a/src/main.c b/src/main.c
index e25ce75..75352f5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -80,6 +80,8 @@ int main(int argc, char *argv[])
z80=Z80Init(SPECWriteMem,
SPECReadMem,
+ SPECWriteWord,
+ SPECReadWord,
SPECWritePort,
SPECReadPort,
SPECReadForDisassem,
@@ -103,6 +105,8 @@ int main(int argc, char *argv[])
while(!quit)
{
+ const char *brk;
+
Z80State s1,s2;
Z80GetState(z80,&s1);
@@ -121,6 +125,12 @@ int main(int argc, char *argv[])
GFXEndFrame(FALSE);
}
+ if ((brk=Break()))
+ {
+ GUIMessage(eMessageBox,"BREAKPOINT","%s",brk);
+ MemoryMenu(z80);
+ }
+
while((e=GFXGetKey()))
{
switch (e->key.keysym.sym)
@@ -132,7 +142,8 @@ int main(int argc, char *argv[])
case SDLK_F1:
if (e->key.state==SDL_PRESSED)
- GUIMessage("HELP",
+ GUIMessage(eMessageBox,
+ "HELP",
"ESC - Quit \n"
"F1 - Help \n"
"F8 - Select tape file for loading\n"
diff --git a/src/memmenu.c b/src/memmenu.c
index 50b9acb..60e2c03 100644
--- a/src/memmenu.c
+++ b/src/memmenu.c
@@ -34,6 +34,7 @@ static const char ident[]="$Id$";
#include "spec.h"
#include "gfx.h"
#include "gui.h"
+#include "util.h"
#include <SDL.h>
@@ -56,13 +57,43 @@ static const char ident_h[]=ESPEC_MEMMENU_H;
#define TRACE "trace"
+/* ---------------------------------------- TYPES
+*/
+typedef struct
+{
+ int no;
+ char **expr;
+} Breakpoint;
+
+
/* ---------------------------------------- STATIC DATA
*/
-FILE *trace=NULL;
+static FILE *trace=NULL;
+static Breakpoint bpoint={NULL,0};
+static const char *brk=NULL;
+
+
+/* ---------------------------------------- PROTOS
+*/
+static int Instruction(Z80 *z80, Z80Val data);
/* ---------------------------------------- PRIVATE FUNCTIONS
*/
+static void SetCallback(Z80 *z80)
+{
+ if (trace || bpoint.no)
+ Z80LodgeCallback(z80,eZ80_Instruction,Instruction);
+}
+
+
+static void ClearCallback(Z80 *z80)
+{
+ if (!trace && !bpoint.no)
+ Z80RemoveCallback(z80,eZ80_Instruction,Instruction);
+}
+
+
static void Centre(const char *p, int y, Uint32 col)
{
GFXPrint((320-strlen(p)*8)/2,y,col,"%s",p);
@@ -73,11 +104,15 @@ static void DisplayMenu(void)
{
static const char *menu[]=
{
- "1. Disassemble/Hex dump",
- "2. Disassemble to file ",
- "3. Start/Stop trace log",
- "4. Playback trace log ",
- "5. Return ",
+ "1. Disassemble/Hex dump ",
+ "2. Disassemble to file ",
+ "3. Start/Stop trace log ",
+ "4. Playback trace log ",
+ "5. Add a new breakpoint ",
+ "6. Clear a breakpoint ",
+ "7. Display breakpoints ",
+ "8. Clear all breakpoints",
+ "9. Return ",
NULL
};
@@ -138,66 +173,26 @@ void DisplayZ80State(Z80State *s, int y, Uint32 col)
}
-static int StrEq(const char *a, const char *b)
-{
- while(*a && *b && tolower(*a)==tolower(*b))
- {
- a++;
- b++;
- }
-
- if (*a || *b)
- return FALSE;
- else
- return TRUE;
-}
-
-
-static Z80Word Address(Z80 *z80, const char *p)
-{
- Z80State s;
-
- Z80GetState(z80,&s);
-
- 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);
-}
-
-
static int EnterAddress(const char *prompt, Z80 *z80, Z80Word *w)
{
- unsigned long ul;
const char *p;
+ char *error;
+ long l;
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;
}
}
@@ -237,7 +232,7 @@ static void DoDisassem(Z80 *z80, const Z80State *s)
curr=pc;
- for(f=0;f<21;f++)
+ for(f=0;f<GFX_HEIGHT/8-8;f++)
{
char s[80];
char *p;
@@ -250,14 +245,27 @@ static void DoDisassem(Z80 *z80, const Z80State *s)
if (hexmode)
{
int n;
+ char asc[9];
for(n=0;n<8;n++)
{
- GFXPrint(40+n*24,y,WHITE,"%2.2x",
- (int)SPECReadForDisassem(z80,curr));
+ Z80Byte b;
+
+ b=SPECReadForDisassem(z80,curr);
+
+ GFXPrint(40+n*24,y,WHITE,"%2.2x",(int)b);
curr++;
+
+ if (isprint(b))
+ asc[n]=b;
+ else
+ asc[n]='.';
}
+
+ asc[8]=0;
+
+ GFXPrint(40+8*24,y,RED,"%s",asc);
}
else
{
@@ -279,7 +287,7 @@ static void DoDisassem(Z80 *z80, const Z80State *s)
{
case SDLK_F1:
GUIMessage
- ("DISASSEMBLY HELP","%s",
+ (eMessageBox, "DISASSEMBLY HELP","%s",
"ESC - Exit \n"
"H - Disassembly/hex \n"
"Enter - Enter address \n"
@@ -362,7 +370,7 @@ static void DoDisassemFile(Z80 *z80, const Z80State *s)
if (!(fp=fopen(fname,"w")))
{
- GUIMessage("ERROR","Couldn't create file:\n%s",fname);
+ GUIMessage(eMessageBox,"ERROR","Couldn't create file:\n%s",fname);
return;
}
@@ -383,10 +391,27 @@ static void DoDisassemFile(Z80 *z80, const Z80State *s)
static int Instruction(Z80 *z80, Z80Val data)
{
- Z80State s;
+ int f;
- Z80GetState(z80,&s);
- fwrite(&s,sizeof s,1,trace);
+ if (trace)
+ {
+ Z80State s;
+
+ Z80GetState(z80,&s);
+
+ fwrite(&s,sizeof s,1,trace);
+ }
+
+ for(f=0;f<bpoint.no;f++)
+ {
+ long l;
+
+ if (Z80Expression(z80,bpoint.expr[f],&l,NULL))
+ {
+ if (l)
+ brk=bpoint.expr[f];
+ }
+ }
return TRUE;
}
@@ -400,12 +425,12 @@ static void EnableTrace(Z80 *z80, Z80State *s)
if (trace)
{
- GUIMessage("NOTICE","Created trace log");
- Z80LodgeCallback(z80,Z80_Instruction,Instruction);
+ GUIMessage(eMessageBox,"NOTICE","Created trace log");
+ SetCallback(z80);
}
else
{
- GUIMessage("ERROR","Failed to create trace log");
+ GUIMessage(eMessageBox,"ERROR","Failed to create trace log");
}
}
}
@@ -415,10 +440,10 @@ static void DisableTrace(Z80 *z80)
{
if (trace)
{
- GUIMessage("NOTICE","Closing current trace log");
+ GUIMessage(eMessageBox,"NOTICE","Closing current trace log");
fclose(trace);
trace=NULL;
- Z80LodgeCallback(z80,Z80_Instruction,NULL);
+ ClearCallback(z80);
}
}
@@ -437,7 +462,7 @@ static void PlaybackTrace(Z80 *z80)
if (!fp)
{
- GUIMessage("ERROR","Couldn't open trace file");
+ GUIMessage(eMessageBox,"ERROR","Couldn't open trace file");
return;
}
@@ -447,7 +472,7 @@ static void PlaybackTrace(Z80 *z80)
if (max_pos==0)
{
- GUIMessage("ERROR","Empty trace file");
+ GUIMessage(eMessageBox,"ERROR","Empty trace file");
fclose(fp);
return;
}
@@ -507,7 +532,7 @@ static void PlaybackTrace(Z80 *z80)
{
case SDLK_F1:
GUIMessage
- ("PLAYBACK HELP","%s",
+ (eMessageBox,"PLAYBACK HELP","%s",
"ESC - Exit \n"
"Enter - Step number \n"
"P - Search for PC \n"
@@ -542,7 +567,7 @@ static void PlaybackTrace(Z80 *z80)
if (rd!=1)
{
- GUIMessage("NOTICE","Address not found");
+ GUIMessage(eMessageBox,"NOTICE","Address not found");
pos=prev_pos;
}
}
@@ -589,6 +614,110 @@ static void PlaybackTrace(Z80 *z80)
}
+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.expr[bpoint.no-1]=StrCopy(expr);
+
+ SetCallback(z80);
+ }
+}
+
+
+static void DoRemoveBreakpoint(Z80 *z80, int delete)
+{
+ if (bpoint.no==0)
+ {
+ if (delete)
+ GUIMessage(eMessageBox,"NOTICE","No breakpoints to delete");
+ else
+ GUIMessage(eMessageBox,"NOTICE","No breakpoints to display");
+
+ return;
+ }
+
+ GFXClear(BLACK);
+
+ if (delete)
+ {
+ int sel;
+
+ sel=GUIListSelect("BREAKPOINT TO DELETE",bpoint.no,bpoint.expr);
+
+ while (sel!=-1)
+ {
+ int f;
+
+ free(bpoint.expr[sel]);
+
+ for(f=sel;f<bpoint.no-1;f++)
+ bpoint.expr[f]=bpoint.expr[f+1];
+
+ bpoint.no--;
+
+ if (bpoint.no==0)
+ {
+ free(bpoint.expr);
+ bpoint.expr=NULL;
+ }
+ else
+ bpoint.expr=Realloc(bpoint.expr,
+ bpoint.no * sizeof(*bpoint.expr));
+
+ ClearCallback(z80);
+
+ sel=GUIListSelect("BREAKPOINT TO DELETE",bpoint.no,bpoint.expr);
+ }
+ }
+ else
+ GUIListSelect("CURRENT BREAKPOINTS",bpoint.no,bpoint.expr);
+}
+
+
+static void DoClearBreakpoint(Z80 *z80)
+{
+ if (GUIMessage(eYesNoBox,"BREAKPOINTS","Clear all breakpoints"))
+ {
+ int f;
+
+ for(f=0;f<bpoint.no;f++)
+ free(bpoint.expr[f]);
+
+ free(bpoint.expr);
+ bpoint.expr=NULL;
+ bpoint.no=0;
+
+ ClearCallback(z80);
+ }
+}
+
+
/* ---------------------------------------- EXPORTED INTERFACES
*/
void MemoryMenu(Z80 *z80)
@@ -631,8 +760,24 @@ void MemoryMenu(Z80 *z80)
PlaybackTrace(z80);
break;
- case SDLK_ESCAPE:
case SDLK_5:
+ DoAddBreakpoint(z80);
+ break;
+
+ case SDLK_6:
+ DoRemoveBreakpoint(z80,TRUE);
+ break;
+
+ case SDLK_7:
+ DoRemoveBreakpoint(z80,FALSE);
+ break;
+
+ case SDLK_8:
+ DoClearBreakpoint(z80);
+ break;
+
+ case SDLK_ESCAPE:
+ case SDLK_9:
quit=TRUE;
break;
@@ -654,4 +799,15 @@ void DisplayState(Z80 *z80)
}
+const char *Break(void)
+{
+ const char *ret;
+
+ ret=brk;
+ brk=NULL;
+
+ return ret;
+}
+
+
/* END OF FILE */
diff --git a/src/memmenu.h b/src/memmenu.h
index 660242f..f04b6b8 100644
--- a/src/memmenu.h
+++ b/src/memmenu.h
@@ -22,8 +22,6 @@
Provides a menu driven interface for analysing memory
- Requires access to the INSTRUCTION Z80 callback.
-
*/
#ifndef ESPEC_MEMMENU_H
@@ -34,12 +32,17 @@
/* Memory menu
*/
-void MemoryMenu(Z80 *z80);
+void MemoryMenu(Z80 *z80);
/* 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/spec.c b/src/spec.c
index bd6d5ff..3be7753 100644
--- a/src/spec.c
+++ b/src/spec.c
@@ -63,8 +63,6 @@ static FILE *tape_out;
/* The SPEC screen
*/
-#define GFX_W 320
-#define GFX_H 300
#define SCR_W 256
#define SCR_H 192
#define TXT_W 32
@@ -75,8 +73,8 @@ static FILE *tape_out;
#define ATTR_AT(x,y) \
mem[ATTR+(x)+((y)/8)*32]
-static const int OFF_X=(GFX_W-SCR_W)/2;
-static const int OFF_Y=(GFX_H-SCR_H)/2;
+static const int OFF_X=(GFX_WIDTH-SCR_W)/2;
+static const int OFF_Y=(GFX_HEIGHT-SCR_H)/2;
static Z80Byte mem[0x10000];
@@ -256,7 +254,7 @@ void DrawScanline(int y)
aline=scanline-TOPL;
- GFXHLine(0,GFX_W-1,y,coltable[border].col);
+ GFXHLine(0,GFX_WIDTH-1,y,coltable[border].col);
if (aline>=0 && aline<SCRL)
{
@@ -335,17 +333,17 @@ static int EDCallback(Z80 *z80, Z80Val data)
case SAVE_PATCH:
if (!tape_out)
{
- state.AF|=Z80_F_Carry;
+ state.AF|=eZ80_Carry;
}
else
{
if (TAPSave(tape_out,HIBYTE(state.AF),&state.IX,&state.DE,mem))
{
- state.AF&=~Z80_F_Carry;
+ state.AF&=~eZ80_Carry;
}
else
{
- state.AF|=Z80_F_Carry;
+ state.AF|=eZ80_Carry;
}
}
break;
@@ -353,17 +351,17 @@ static int EDCallback(Z80 *z80, Z80Val data)
case LOAD_PATCH:
if (!tape_in)
{
- state.AF|=Z80_F_Carry;
+ state.AF|=eZ80_Carry;
}
else
{
if (TAPLoad(tape_in,HIBYTE(state.AF),&state.IX,&state.DE,mem))
{
- state.AF&=~Z80_F_Carry;
+ state.AF&=~eZ80_Carry;
}
else
{
- state.AF|=Z80_F_Carry;
+ state.AF|=eZ80_Carry;
}
}
break;
@@ -412,7 +410,7 @@ static int CheckTimers(Z80 *z80, Z80Val val)
*/
y=scanline-TOPL+OFF_Y;
- if (y>=0 && y<GFX_H)
+ if (y>=0 && y<GFX_HEIGHT)
DrawScanline(y);
/* TODO: Process sound emulation */
@@ -433,23 +431,28 @@ void SPECInit(Z80 *z80)
if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb")))
{
- GUIMessage("ERROR","Failed to open Spectrum ROM\n%s",
- SConfig(CONF_ROMFILE));
+ GUIMessage(eMessageBox,
+ "ERROR",
+ "Failed to open Spectrum 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);
/* Set up the keyboard
*/
@@ -533,6 +536,25 @@ void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val)
}
+Z80Word SPECReadWord(Z80 *z80, Z80Word addr)
+{
+ /* TODO: Emulation of contention */
+ return (Z80Word)mem[addr]|(Z80Word)mem[addr+1]<<8;
+}
+
+
+void SPECWriteWord(Z80 *z80, Z80Word addr, Z80Word val)
+{
+ if (addr>=ROMLEN)
+ mem[addr]=val&0xff;
+
+ addr++;
+
+ if (addr>=ROMLEN)
+ mem[addr]=val>>8;
+}
+
+
Z80Byte SPECReadPort(Z80 *z80, Z80Word port)
{
Z80Byte lo=port&0xff;
diff --git a/src/spec.h b/src/spec.h
index bb62b91..f771480 100644
--- a/src/spec.h
+++ b/src/spec.h
@@ -21,8 +21,6 @@
-------------------------------------------------------------------------
Provides the emulation for the SPEC
-
- Requires access to the HOOK and FETCH Z80 callbacks
*/
#ifndef ESPEC_SPECH
@@ -48,6 +46,8 @@ void SPECKeyEvent(SDL_Event *e);
*/
Z80Byte SPECReadMem(Z80 *z80, Z80Word addr);
void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val);
+Z80Word SPECReadWord(Z80 *z80, Z80Word addr);
+void SPECWriteWord(Z80 *z80, Z80Word addr, Z80Word val);
Z80Byte SPECReadPort(Z80 *z80, Z80Word port);
void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val);
Z80Byte SPECReadForDisassem(Z80 *z80, Z80Word addr);
diff --git a/src/util.c b/src/util.c
index c3396eb..a8a037d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -42,12 +42,23 @@ static const char ident_h[]=ESPEC_UTIL_H;
*/
void *Malloc(size_t size)
{
- void *p=malloc(size);
+ void *new=malloc(size);
- if (!p)
+ if (!new)
Exit("malloc failed for %lu bytes\n",(unsigned long)size);
- return p;
+ 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;
}
diff --git a/src/util.h b/src/util.h
index f391170..6930b8a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -37,6 +37,11 @@
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);