summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2003-12-22 00:01:31 +0000
committerIan C <ianc@noddybox.co.uk>2003-12-22 00:01:31 +0000
commita500f050272a8cca97ed0bbb7f8d7156555c61a7 (patch)
tree879d83916f2dae38e3574c4937098e40ae27bdb0
parent9443eab98692b668fd35fc2a7e2cfb043953dbc7 (diff)
Added memory menu and some devel changes
-rw-r--r--src/Makefile95
-rw-r--r--src/config.c5
-rw-r--r--src/config.h3
-rw-r--r--src/gfx.c52
-rw-r--r--src/gfx.h12
-rw-r--r--src/gui.c63
-rw-r--r--src/gui.h9
-rw-r--r--src/main.c72
-rw-r--r--src/memmenu.c329
-rw-r--r--src/memmenu.h46
-rw-r--r--src/zx81.c524
-rw-r--r--src/zx81.h11
12 files changed, 1089 insertions, 132 deletions
diff --git a/src/Makefile b/src/Makefile
index 9486c2b..ba51a7e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -18,7 +18,7 @@
#
# -------------------------------------------------------------------------
#
-# $Id: Makefile,v 1.4 2003-12-19 19:31:57 ianc Exp $
+# $Id: Makefile,v 1.5 2003-12-22 00:01:31 ianc Exp $
#
@@ -37,6 +37,7 @@ SOURCE = main.c \
config.c \
gfx.c \
gui.c \
+ memmenu.c \
exit.c
OBJECTS = main.o \
@@ -44,6 +45,7 @@ OBJECTS = main.o \
config.o \
gfx.o \
gui.o \
+ memmenu.o \
exit.o
EMMA = emma
@@ -72,94 +74,3 @@ depend:
cd z80; make depend ; cd ..
# DO NOT DELETE THIS LINE -- make depend depends on it
-
-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/local/include/SDL/SDL_getenv.h
-main.o: /usr/local/include/SDL/SDL_error.h
-main.o: /usr/local/include/SDL/begin_code.h
-main.o: /usr/local/include/SDL/close_code.h
-main.o: /usr/local/include/SDL/SDL_rwops.h /usr/local/include/SDL/SDL_timer.h
-main.o: /usr/local/include/SDL/SDL_audio.h
-main.o: /usr/local/include/SDL/SDL_byteorder.h
-main.o: /usr/local/include/SDL/SDL_cdrom.h
-main.o: /usr/local/include/SDL/SDL_joystick.h
-main.o: /usr/local/include/SDL/SDL_events.h
-main.o: /usr/local/include/SDL/SDL_active.h
-main.o: /usr/local/include/SDL/SDL_keyboard.h
-main.o: /usr/local/include/SDL/SDL_keysym.h
-main.o: /usr/local/include/SDL/SDL_mouse.h /usr/local/include/SDL/SDL_video.h
-main.o: /usr/local/include/SDL/SDL_mutex.h /usr/local/include/SDL/SDL_quit.h
-main.o: /usr/local/include/SDL/SDL_version.h z80/z80.h zx81.h gfx.h gui.h
-main.o: config.h exit.h
-zx81.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
-zx81.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
-zx81.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
-zx81.o: zx81.h z80/z80.h config.h exit.h
-config.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
-config.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
-config.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
-config.o: exit.h config.h
-gfx.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
-gfx.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
-gfx.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
-gfx.o: /usr/include/stdarg.h gfx.h /usr/local/include/SDL/SDL.h
-gfx.o: /usr/local/include/SDL/SDL_main.h /usr/local/include/SDL/SDL_types.h
-gfx.o: /usr/local/include/SDL/SDL_getenv.h /usr/local/include/SDL/SDL_error.h
-gfx.o: /usr/local/include/SDL/begin_code.h
-gfx.o: /usr/local/include/SDL/close_code.h /usr/local/include/SDL/SDL_rwops.h
-gfx.o: /usr/local/include/SDL/SDL_timer.h /usr/local/include/SDL/SDL_audio.h
-gfx.o: /usr/local/include/SDL/SDL_byteorder.h
-gfx.o: /usr/local/include/SDL/SDL_cdrom.h
-gfx.o: /usr/local/include/SDL/SDL_joystick.h
-gfx.o: /usr/local/include/SDL/SDL_events.h
-gfx.o: /usr/local/include/SDL/SDL_active.h
-gfx.o: /usr/local/include/SDL/SDL_keyboard.h
-gfx.o: /usr/local/include/SDL/SDL_keysym.h /usr/local/include/SDL/SDL_mouse.h
-gfx.o: /usr/local/include/SDL/SDL_video.h /usr/local/include/SDL/SDL_mutex.h
-gfx.o: /usr/local/include/SDL/SDL_quit.h /usr/local/include/SDL/SDL_version.h
-gfx.o: exit.h config.h font.h
-gui.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
-gui.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
-gui.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
-gui.o: /usr/include/stdarg.h gui.h /usr/local/include/SDL/SDL.h
-gui.o: /usr/local/include/SDL/SDL_main.h /usr/local/include/SDL/SDL_types.h
-gui.o: /usr/local/include/SDL/SDL_getenv.h /usr/local/include/SDL/SDL_error.h
-gui.o: /usr/local/include/SDL/begin_code.h
-gui.o: /usr/local/include/SDL/close_code.h /usr/local/include/SDL/SDL_rwops.h
-gui.o: /usr/local/include/SDL/SDL_timer.h /usr/local/include/SDL/SDL_audio.h
-gui.o: /usr/local/include/SDL/SDL_byteorder.h
-gui.o: /usr/local/include/SDL/SDL_cdrom.h
-gui.o: /usr/local/include/SDL/SDL_joystick.h
-gui.o: /usr/local/include/SDL/SDL_events.h
-gui.o: /usr/local/include/SDL/SDL_active.h
-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
-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
-exit.o: /usr/local/include/SDL/SDL_main.h /usr/local/include/SDL/SDL_types.h
-exit.o: /usr/local/include/SDL/SDL_getenv.h
-exit.o: /usr/local/include/SDL/SDL_error.h
-exit.o: /usr/local/include/SDL/begin_code.h
-exit.o: /usr/local/include/SDL/close_code.h
-exit.o: /usr/local/include/SDL/SDL_rwops.h /usr/include/stdio.h
-exit.o: /usr/local/include/SDL/SDL_timer.h /usr/local/include/SDL/SDL_audio.h
-exit.o: /usr/local/include/SDL/SDL_byteorder.h
-exit.o: /usr/local/include/SDL/SDL_cdrom.h
-exit.o: /usr/local/include/SDL/SDL_joystick.h
-exit.o: /usr/local/include/SDL/SDL_events.h
-exit.o: /usr/local/include/SDL/SDL_active.h
-exit.o: /usr/local/include/SDL/SDL_keyboard.h
-exit.o: /usr/local/include/SDL/SDL_keysym.h
-exit.o: /usr/local/include/SDL/SDL_mouse.h /usr/local/include/SDL/SDL_video.h
-exit.o: /usr/local/include/SDL/SDL_mutex.h /usr/local/include/SDL/SDL_quit.h
-exit.o: /usr/local/include/SDL/SDL_version.h
-emma.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
-emma.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
-emma.o: /usr/include/stdio.h z80/z80.h
diff --git a/src/config.c b/src/config.c
index 3fdb00a..0614c64 100644
--- a/src/config.c
+++ b/src/config.c
@@ -50,6 +50,7 @@ static int fullscreen=FALSE;
static int memsize=16;
static int frames=50;
static int scale=1;
+static int trace=0;
static const struct
{
@@ -63,6 +64,7 @@ static const struct
{"memsize", &memsize, TRUE},
{"frames", &frames, TRUE},
{"scale", &scale, TRUE},
+ {"trace", &trace, TRUE},
{NULL, NULL, FALSE}
};
@@ -151,7 +153,8 @@ int IConfig(IConfigVar v)
&fullscreen,
&memsize,
&frames,
- &scale
+ &scale,
+ &trace
};
return *vars[v];
diff --git a/src/config.h b/src/config.h
index d937cb6..4613db3 100644
--- a/src/config.h
+++ b/src/config.h
@@ -35,7 +35,8 @@ typedef enum
CONF_FULLSCREEN,
CONF_MEMSIZE,
CONF_FRAMES_PER_SEC,
- CONF_SCALE
+ CONF_SCALE,
+ CONF_TRACE
} IConfigVar;
diff --git a/src/gfx.c b/src/gfx.c
index 57be20c..e7cecb8 100644
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -225,6 +225,16 @@ void GFXEndFrame(int delay)
}
+void GFXKeyRepeat(int repeat)
+{
+ if (repeat)
+ SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
+ SDL_DEFAULT_REPEAT_INTERVAL);
+ else
+ SDL_EnableKeyRepeat(0,0);
+}
+
+
SDL_Event *GFXGetKey(void)
{
static SDL_Event e;
@@ -246,7 +256,7 @@ SDL_Event *GFXWaitKey(void)
do
{
SDL_WaitEvent(&e);
- } while (e.type!=SDL_KEYUP);
+ } while (e.type!=SDL_KEYDOWN);
return &e;
}
@@ -342,4 +352,44 @@ void GFXPrint(int x, int y, Uint32 col, const char *format, ...)
}
+void GFXPrintPaper(int x, int y, Uint32 col, Uint32 paper,
+ const char *format, ...)
+{
+ char buff[257];
+ va_list va;
+ char *p;
+ int sx,sy;
+
+ va_start(va,format);
+ vsprintf(buff,format,va);
+ va_end(va);
+
+ p=buff;
+
+ LOCK;
+
+ while(*p)
+ {
+ for(sy=0;sy<8;sy++)
+ {
+ if (y+sy<SCR_H && x<SCR_W)
+ {
+ for(sx=0;sx<8;sx++)
+ {
+ if (font[(int)*p][sx+sy*8] && x+sx<SCR_W)
+ putpixel(x+sx,y+sy,col);
+ else
+ putpixel(x+sx,y+sy,paper);
+ }
+ }
+ }
+
+ p++;
+ x+=8;
+ }
+
+ UNLOCK;
+}
+
+
/* END OF FILE */
diff --git a/src/gfx.h b/src/gfx.h
index 93eef60..14394d8 100644
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -77,6 +77,11 @@ void GFXStartFrame(void);
void GFXEndFrame(int delay);
+/* Set key repeat
+*/
+void GFXKeyRepeat(int repeat);
+
+
/* Suck out keyboard events. Returns NULL if no more keyboard events
*/
SDL_Event *GFXGetKey(void);
@@ -125,6 +130,13 @@ void GFXVLine(int x, int y1, int y2, Uint32 col);
void GFXPrint(int x, int y, Uint32 col, const char *format, ...);
+/* As above, but draws text using the supplied background colour, rather
+ than transparently.
+*/
+void GFXPrintPaper(int x, int y, Uint32 col, Uint32 paper,
+ const char *format, ...);
+
+
#endif
diff --git a/src/gui.c b/src/gui.c
index bda46d3..19b39dc 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -29,6 +29,7 @@ static const char ident[]="$Id$";
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <ctype.h>
#include "gui.h"
#include "gfx.h"
@@ -79,7 +80,7 @@ static void Centre(const char *p, int y, int r, int g, int b)
*/
void GUIMessage(const char *title, const char *format,...)
{
- char buff[257];
+ char buff[1025];
va_list va;
char *p;
int no;
@@ -119,6 +120,13 @@ void GUIMessage(const char *title, const char *format,...)
width=(width*8)+16;
height=(no+3)*10;
+
+ if (width>(SCR_W-10))
+ width=SCR_W-10;
+
+ if (height>(SCR_H-10))
+ height=SCR_H-10;
+
y=(SCR_H-height)/2;
x=(SCR_W-width)/2;
@@ -146,4 +154,57 @@ void GUIMessage(const char *title, const char *format,...)
}
+const char *GUIInputString(const char *prompt, const char *orig)
+{
+ static const int y_pos=SCR_H-8;
+ static char buff[41];
+ size_t len;
+ int done=FALSE;
+ SDL_Event *e;
+
+ buff[0]=0;
+ strncat(buff,orig,40);
+ len=strlen(buff);
+
+ 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);
+ GFXEndFrame(FALSE);
+
+ e=GFXWaitKey();
+
+ switch(e->key.keysym.sym)
+ {
+ case SDLK_RETURN:
+ case SDLK_KP_ENTER:
+ done=TRUE;
+ break;
+
+ case SDLK_ESCAPE:
+ buff[0]=0;
+ len=0;
+ break;
+
+ case SDLK_BACKSPACE:
+ case SDLK_DELETE:
+ if (len)
+ buff[--len]=0;
+
+ break;
+
+ default:
+ if (len<40 && isprint(e->key.keysym.sym))
+ {
+ buff[len++]=(char)e->key.keysym.sym;
+ buff[len]=0;
+ }
+ break;
+ }
+ }
+
+ return buff;
+}
+
+
/* END OF FILE */
diff --git a/src/gui.h b/src/gui.h
index 02a5db5..4f03394 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -33,10 +33,15 @@
/* ---------------------------------------- INTERFACES
*/
-/* Display a simple message box. A message of longer than 256 bytes causes
+/* Display a simple message box. A message of longer than 1024 bytes causes
undefined behaviour. Newlines cause a line break.
*/
-void GUIMessage(const char *title, const char *format,...);
+void GUIMessage(const char *title, const char *format,...);
+
+
+/* Enter a string, max 40 characters
+*/
+const char *GUIInputString(const char *prompt, const char *orig);
#endif
diff --git a/src/main.c b/src/main.c
index d4bb65d..8841f6e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -32,6 +32,7 @@ static const char id[]="$Id$";
#include "zx81.h"
#include "gfx.h"
#include "gui.h"
+#include "memmenu.h"
#include "config.h"
#include "exit.h"
@@ -63,10 +64,13 @@ static Uint32 grey;
int main(int argc, char *argv[])
{
Z80 *z80;
+ SDL_Event *e;
+ int quit;
+ int trace;
ConfigRead();
- ZX81Init();
+ trace=IConfig(CONF_TRACE);
z80=Z80Init(ZX81WriteMem,
ZX81ReadMem,
@@ -77,44 +81,58 @@ int main(int argc, char *argv[])
GFXInit();
+ ZX81Init(z80);
+
white=GFXRGB(255,255,255);
grey=GFXRGB(128,128,128);
black=GFXRGB(0,0,0);
- GFXClear(grey);
- GFXPrint(1,1,black,"Quick SDL check");
- GFXPrint(2,2,white,"Quick SDL check");
- GFXRect(100,100,20,20,black,TRUE);
- GFXRect(99,99,22,22,white,FALSE);
-
- GFXRect(80,80,1,1,black,TRUE);
- GFXRect(80,90,1,1,black,FALSE);
-
- GFXRect(90,80,2,2,black,TRUE);
- GFXRect(90,90,2,2,black,FALSE);
-
- GFXRect(100,80,3,3,black,TRUE);
- GFXRect(100,90,3,3,black,FALSE);
-
- GFXHLine(0,319,0,white);
- GFXVLine(0,1,199,black);
-
- {
- int f;
+ quit=FALSE;
- for(f=0;f<10;f++)
+ while(!quit)
{
- GFXPlot(rand()%320,rand()%200,white);
- GFXEndFrame(FALSE);
- }
+ Z80SingleStep(z80);
+
+ if (trace)
+ {
+ DisplayState(z80);
+ GFXEndFrame(FALSE);
+ }
+
+ while((e=GFXGetKey()))
+ {
+ switch (e->key.keysym.sym)
+ {
+ case SDLK_ESCAPE:
+ if (e->key.state==SDL_RELEASED)
+ quit=TRUE;
+ break;
+
+ case SDLK_F11:
+ if (e->key.state==SDL_RELEASED)
+ MemoryMenu(z80);
+ break;
+
+ case SDLK_F12:
+ if (e->key.state==SDL_RELEASED)
+ trace=!trace;
+ break;
+
+ default:
+ ZX81KeyEvent(e);
+ break;
+ }
+ }
}
- GUIMessage("Test Message","Hello\nWorld\n%s",SConfig(CONF_TAPEDIR));
-
SDL_Quit();
return EXIT_SUCCESS;
}
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+
+
/* END OF FILE */
diff --git a/src/memmenu.c b/src/memmenu.c
new file mode 100644
index 0000000..c2f5da7
--- /dev/null
+++ b/src/memmenu.c
@@ -0,0 +1,329 @@
+/*
+
+ ezx81 - X11 ZX81 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
+
+ -------------------------------------------------------------------------
+
+ Provides a common error exit point
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "memmenu.h"
+#include "zx81.h"
+#include "gfx.h"
+#include "gui.h"
+
+#include <SDL.h>
+
+static const char ident_h[]=EZX81_MEMMENU_H;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#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 MENU
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static void Centre(const char *p, int y, Uint32 col)
+{
+ GFXPrint((320-strlen(p)*8)/2,y,col,"%s",p);
+}
+
+
+static void DisplayMenu(void)
+{
+ static const char *menu[]=
+ {
+ "1. Disassemble/Hex dump",
+ "2. Return ",
+ NULL
+ };
+
+ int f;
+
+ GFXClear(BLACK);
+
+ Centre("MEMORY MENU",0,WHITE);
+ Centre("Select an option",8,WHITE);
+
+ f=0;
+
+ while(menu[f])
+ {
+ Centre(menu[f],20+f*10,WHITE);
+ f++;
+ }
+}
+
+
+static const char *FlagString(Z80Byte flag)
+{
+ static char s[]="76543210";
+ static char c[]="SZ5H3PNC";
+ int f;
+
+ for(f=0;f<8;f++)
+ if (flag&(1<<(7-f)))
+ s[f]=c[f];
+ else
+ s[f]='-';
+
+ return s;
+}
+
+
+static int EnterAddress(Z80Word *w)
+{
+ unsigned long ul;
+ const char *p;
+
+ p=GUIInputString("Address?","");
+
+ if (*p)
+ {
+ ul=strtoul(p,NULL,0);
+
+ if (ul>0xffff)
+ {
+ GUIMessage("ERROR","Bad address");
+ }
+ else
+ {
+ *w=(Z80Word)ul;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+static void DoDisassem(Z80 *z80, const Z80State *s)
+{
+ static int hexmode=FALSE;
+ Z80Word pc=s->PC;
+ int quit=FALSE;
+
+ while(!quit)
+ {
+ SDL_Event *e;
+ Z80Word curr;
+ Z80Word next;
+ int f;
+
+ GFXClear(BLACK);
+
+ Centre("Press F1 for help",0,RED);
+
+ curr=pc;
+
+ for(f=0;f<21;f++)
+ {
+ char s[80];
+ char *p;
+ int y;
+
+ y=16+f*8;
+
+ GFXPrint(0,y,GREEN,"%4.4x",curr);
+
+ if (hexmode)
+ {
+ int n;
+
+ for(n=0;n<8;n++)
+ {
+ GFXPrint(40+n*24,y,WHITE,"%2.2x",
+ (int)ZX81ReadForDisassem(z80,curr));
+
+ curr++;
+ }
+ }
+ else
+ {
+ strcpy(s,Z80Disassemble(z80,&curr));
+
+ p=strtok(s,";");
+ GFXPrint(40,y,WHITE,"%s",p);
+ }
+
+ if (f==0)
+ next=curr;
+ }
+
+ GFXEndFrame(FALSE);
+
+ e=GFXWaitKey();
+
+ switch(e->key.keysym.sym)
+ {
+ case SDLK_F1:
+ GUIMessage
+ ("DISASSEMBLY HELP","%s",
+ "ESC - Exit\n"
+ "H - Switch between disassembly/hex\n"
+ "Enter - Enter address to display\n"
+ "Cursor Up - Prev op\n"
+ "Cursor Down - Next op\n"
+ "Page Up - Move back a page\n"
+ "Page Down - Move forward a page\n"
+ "Cursor Left - Move PC by -1024\n"
+ "Cursor Right - Move PC by 1024");
+ break;
+
+ case SDLK_ESCAPE:
+ quit=TRUE;
+ break;
+
+ case SDLK_h:
+ hexmode=!hexmode;
+ break;
+
+ case SDLK_RETURN:
+ case SDLK_KP_ENTER:
+ EnterAddress(&pc);
+ break;
+
+ case SDLK_UP:
+ if (hexmode)
+ pc-=8;
+ else
+ pc--;
+ break;
+
+ case SDLK_DOWN:
+ pc=next;
+ break;
+
+ case SDLK_PAGEUP:
+ if (hexmode)
+ pc-=21*8;
+ else
+ pc-=21;
+ break;
+
+ case SDLK_PAGEDOWN:
+ pc=curr;
+ break;
+
+ case SDLK_LEFT:
+ pc-=1024;
+ break;
+
+ case SDLK_RIGHT:
+ pc+=1024;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/* ---------------------------------------- EXPORTED INTERFACES
+*/
+void MemoryMenu(Z80 *z80)
+{
+ SDL_Event *e;
+ int quit=FALSE;
+ Z80State s;
+
+ Z80GetState(z80,&s);
+
+ GFXKeyRepeat(TRUE);
+
+ while(!quit)
+ {
+ DisplayMenu();
+ DisplayState(z80);
+ GFXEndFrame(FALSE);
+
+ e=GFXWaitKey();
+
+ switch(e->key.keysym.sym)
+ {
+ case SDLK_1:
+ DoDisassem(z80,&s);
+ break;
+
+ case SDLK_ESCAPE:
+ case SDLK_2:
+ quit=TRUE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ GFXKeyRepeat(FALSE);
+}
+
+
+void DisplayState(Z80 *z80)
+{
+ Z80State s;
+ int y;
+
+ Z80GetState(z80,&s);
+
+ 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;
+
+ GFXPrintPaper(0,y,RED,BLACK,"IFF1=%2.2x IFF2=%2.2x",s.IFF1,s.IFF2);
+ y+=8;
+
+ y+=8;
+ GFXPrintPaper(0,y,RED,BLACK,"%s\n",ZX81Info(z80));
+ y+=8;
+}
+
+
+
+
+/* END OF FILE */
diff --git a/src/memmenu.h b/src/memmenu.h
new file mode 100644
index 0000000..bacbef9
--- /dev/null
+++ b/src/memmenu.h
@@ -0,0 +1,46 @@
+/*
+
+ ezx81 - X11 ZX81 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
+
+ -------------------------------------------------------------------------
+
+ Provides a menu driven interface for analysing memory
+
+*/
+
+#ifndef EZX81_MEMMENU_H
+#define EZX81_MEMMENU_H "$Id$"
+
+#include "z80.h"
+
+
+/* Memory menu
+*/
+void MemoryMenu(Z80 *z80);
+
+
+/* Display the state of the ZX81 at the bottom of the screen
+*/
+void DisplayState(Z80 *z80);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/zx81.c b/src/zx81.c
index 9fa09f6..515cd07 100644
--- a/src/zx81.c
+++ b/src/zx81.c
@@ -29,11 +29,21 @@ static const char ident[]="$Id$";
#include <stdio.h>
#include <string.h>
#include "zx81.h"
+#include "gfx.h"
+#include "gui.h"
#include "config.h"
#include "exit.h"
static const char ident_h[]=EZX81ZX81H;
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
/* ---------------------------------------- STATICS
*/
@@ -41,6 +51,17 @@ 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)
+*/
+static const int 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;
+
/* These assume a 320x200 screen
*/
static const int OFF_X=(320-256)/2;
@@ -52,30 +73,377 @@ static Z80Word RAMBOT=0;
static Z80Word RAMTOP=0;
static Z80Word RAMLEN=0;
+/* Counter used when triggering the interrupts for the display
+*/
+static int nmigen=FALSE;
+static int hsync=FALSE;
+
+/* The ULA
+*/
+static struct
+{
+ int x;
+ int y;
+ int c;
+ int release;
+} ULA;
+
+/* GFX vars
+*/
+static Uint32 white;
+static Uint32 black;
+
+
+/* The keyboard
+*/
+static Z80Byte matrix[8];
+
+typedef struct
+{
+ SDLKey key;
+ int m1,b1,m2,b2;
+} MatrixMap;
+
+#define KY1(m,b) m,1<<b,-1,-1
+#define KY2(m1,b1,m2,b2) m1,1<<b1,m2,1<<b2
+
+static const MatrixMap keymap[]=
+{
+ {SDLK_1, KY1(3,0)},
+ {SDLK_2, KY1(3,1)},
+ {SDLK_3, KY1(3,2)},
+ {SDLK_4, KY1(3,3)},
+ {SDLK_5, KY1(3,4)},
+ {SDLK_6, KY1(4,4)},
+ {SDLK_7, KY1(4,3)},
+ {SDLK_8, KY1(4,2)},
+ {SDLK_9, KY1(4,1)},
+ {SDLK_0, KY1(4,0)},
+
+ {SDLK_a, KY1(1,0)},
+ {SDLK_b, KY1(7,4)},
+ {SDLK_c, KY1(0,3)},
+ {SDLK_d, KY1(1,2)},
+ {SDLK_e, KY1(2,2)},
+ {SDLK_f, KY1(1,3)},
+ {SDLK_g, KY1(1,4)},
+ {SDLK_h, KY1(6,4)},
+ {SDLK_i, KY1(5,2)},
+ {SDLK_j, KY1(6,3)},
+ {SDLK_k, KY1(6,2)},
+ {SDLK_l, KY1(6,1)},
+ {SDLK_m, KY1(7,2)},
+ {SDLK_n, KY1(7,3)},
+ {SDLK_o, KY1(5,1)},
+ {SDLK_p, KY1(5,0)},
+ {SDLK_q, KY1(2,0)},
+ {SDLK_r, KY1(2,3)},
+ {SDLK_s, KY1(1,1)},
+ {SDLK_t, KY1(2,4)},
+ {SDLK_u, KY1(5,3)},
+ {SDLK_v, KY1(0,4)},
+ {SDLK_w, KY1(2,1)},
+ {SDLK_x, KY1(0,2)},
+ {SDLK_y, KY1(5,4)},
+ {SDLK_z, KY1(0,1)},
+
+ {SDLK_RETURN, KY1(6,0)},
+ {SDLK_SPACE, KY1(7,0)},
+
+ {SDLK_COMMA, KY1(7,1)}, /* In the right place... */
+ {SDLK_PERIOD, KY1(7,1)}, /* ...or the right key... */
+
+ {SDLK_BACKSPACE, KY2(0,0,4,0)},
+ {SDLK_DELETE, KY2(0,0,4,0)},
+ {SDLK_UP, KY2(0,0,4,3)},
+ {SDLK_DOWN, KY2(0,0,4,4)},
+ {SDLK_LEFT, KY2(0,0,3,4)},
+ {SDLK_RIGHT, KY2(0,0,4,2)},
+
+ {SDLK_RSHIFT, KY1(0,0)},
+ {SDLK_LSHIFT, KY1(0,0)},
+
+ {SDLK_UNKNOWN, 0,0,0,0},
+};
+
/* ---------------------------------------- PRIVATE FUNCTIONS
*/
-void ULA_Video_Shifter(Z80 *z80, Z80Byte val)
+static void RomPatch(void)
+{
+ static const Z80Byte save[]=
+ {
+ 0xed, 0xf0, /* ED F0 illegal op */
+ 0xc3, 0x08, 0x02, /* JP $0207 */
+ 0xff /* End of patch */
+ };
+
+ static const Z80Byte load[]=
+ {
+ 0xed, 0xf1, /* ED F0 illegal op */
+ 0xc3, 0x08, 0x02, /* JP $0207 */
+ 0xff /* End of patch */
+ };
+
+ int f;
+
+ for(f=0;save[f]!=0xff;f++)
+ mem[ROM_SAVE+f]=save[f];
+
+ for(f=0;load[f]!=0xff;f++)
+ mem[ROM_LOAD+f]=load[f];
+}
+
+
+static char ToASCII(Z80Byte b)
+{
+ if (b==0) /* SPACE */
+ return ' ';
+
+ if (b==22) /* Dash (-) */
+ return '-';
+
+ if (b>=28 && b<=37) /* 0-9 */
+ return '0'+b-28;
+
+ if (b>=38 && b<=63) /* A-Z */
+ return 'a'+b-38;
+
+ return 0;
+}
+
+
+static const char *ConvertFilename(Z80Word addr)
+{
+ static char buff[FILENAME_MAX];
+ char *p;
+
+ p=buff;
+ *p=0;
+
+ if (addr>0x8000)
+ return buff;
+
+ do
+ {
+ char c=ToASCII(mem[addr]&0x7f);
+
+ if (c)
+ *p++=c;
+
+ } while(mem[addr++]<0x80);
+
+ *p=0;
+
+ return buff;
+}
+
+
+static void LoadTape(Z80State *state)
+{
+ const char *p=ConvertFilename(state->DE);
+ char path[FILENAME_MAX];
+ FILE *fp;
+ Z80Word addr;
+ int c;
+
+ if (strlen(p)==0)
+ {
+ GUIMessage("ERROR","Can't load empty filename");
+ return;
+ }
+
+ strcpy(path,SConfig(CONF_TAPEDIR));
+ strcat(path,"/");
+ strcat(path,p);
+ strcat(path,".p");
+
+ if (!(fp=fopen(path,"rb")))
+ {
+ GUIMessage("ERROR","Can't load file:\n%s",path);
+ return;
+ }
+
+ addr=0x4009;
+
+ while((c=getc(fp))!=EOF)
+ {
+ if (addr>=0x4000)
+ mem[addr]=(Z80Byte)c;
+
+ addr++;
+ }
+
+ fclose(fp);
+}
+
+
+static void SaveTape(Z80State *state)
+{
+ const char *p=ConvertFilename(state->DE);
+ char path[FILENAME_MAX];
+ FILE *fp;
+ Z80Word start;
+ Z80Word end;
+
+ if (strlen(p)==0)
+ {
+ GUIMessage("ERROR","Can't save empty filename");
+ return;
+ }
+
+ strcpy(path,SConfig(CONF_TAPEDIR));
+ strcat(path,"/");
+ strcat(path,p);
+ strcat(path,".p");
+
+ if (!(fp=fopen(path,"wb")))
+ {
+ GUIMessage("ERROR","Can't write file:\n%s",path);
+ return;
+ }
+
+ start=0x4009;
+ end=(Z80Word)mem[0x4014]|(Z80Word)mem[0x4015]<<8;
+
+ while(start<=end)
+ putc(mem[start++],fp);
+
+ fclose(fp);
+}
+
+
+static int EDCallback(Z80 *z80, Z80Val data)
{
+ Z80State state;
+
+ Z80GetState(z80,&state);
+
+ switch((Z80Byte)data)
+ {
+ case 0xf0:
+ SaveTape(&state);
+ break;
+
+ case 0xf1:
+ LoadTape(&state);
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+
+static void ULA_Video_Shifter(Z80 *z80, Z80Byte val)
+{
+ Z80State state;
+ Z80Word base;
+ int x,y;
+ int inv;
+ int b;
+
+ Z80GetState(z80,&state);
+
+ /* Extra check due to out dodgy ULA emulation
+ */
+ if (ULA.y>=0 && ULA.y<SCR_H)
+ {
+ Uint32 fg,bg;
+
+ /* Position on screen corresponding to ULA
+ */
+ x=OFF_X+ULA.x*8;
+ y=OFF_Y+ULA.y;
+
+ /* Get ULA invert state and clear to ULA 6-but code
+ */
+ inv=val&0x80;
+ val&=0x3f;
+
+ base=((Z80Word)state.I<<8)|(val<<3)|ULA.c;
+
+ if (inv)
+ {
+ fg=white;
+ bg=black;
+ }
+ else
+ {
+ fg=black;
+ bg=white;
+ }
+
+ for(b=0;b<8;b++)
+ {
+ if (mem[base]&(1<<(7-b)))
+ GFXPlot(x+b,y,fg);
+ else
+ GFXPlot(x+b,y,bg);
+ }
+ }
+
+ ULA.x=(ULA.x+1)&0x1f;
+
+ if (ULA.x==0)
+ Z80Interrupt(z80,0xff);
+}
+
+
+static int CheckTimers(Z80 *z80, Z80Val val)
+{
+ if (val>HSYNC_PERIOD)
+ {
+ Z80ResetCycles(z80,0);
+
+ if (nmigen)
+ {
+ Z80NMI(z80,0xff);
+ }
+ else if (hsync)
+ {
+ if (ULA.release)
+ {
+ /* ULA.release=FALSE; */
+ ULA.c=(ULA.c+1)&7;
+ ULA.y++;
+ ULA.x=0;
+ }
+ }
+ }
+
+ return TRUE;
}
/* ---------------------------------------- EXPORTED INTERFACES
*/
-void ZX81Init(void)
+void ZX81Init(Z80 *z80)
{
FILE *fp;
Z80Word f;
if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb")))
- Exit("Failed to open ZX81 ROM - %s\n",SConfig(CONF_ROMFILE));
+ {
+ GUIMessage("ERROR","Failed to open ZX81 ROM\n%s",SConfig(CONF_ROMFILE));
+ Exit("");
+ }
if (fread(mem,1,ROMLEN,fp)!=ROMLEN)
{
fclose(fp);
- Exit("ROM file must be %d bytes long\n",ROMLEN);
+ GUIMessage("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);
+
/* Mirror the ROM
*/
memcpy(mem+ROMLEN,mem,ROMLEN);
@@ -93,6 +461,48 @@ void ZX81Init(void)
for(f=RAMBOT;f<=RAMTOP;f++)
mem[f]=0;
+
+ for(f=0;f<8;f++)
+ matrix[f]=0x1f;
+
+ white=GFXRGB(230,230,230);
+ black=GFXRGB(0,0,0);
+
+ nmigen=FALSE;
+ hsync=FALSE;
+
+ GFXStartFrame();
+}
+
+
+void ZX81KeyEvent(SDL_Event *e)
+{
+ const MatrixMap *m;
+
+ m=keymap;
+
+ while(m->key!=SDLK_UNKNOWN)
+ {
+ if (e->key.keysym.sym==m->key)
+ {
+ if (e->key.state==SDL_PRESSED)
+ {
+ matrix[m->m1]&=~m->b1;
+
+ if (m->m2!=-1)
+ matrix[m->m2]&=~m->b2;
+ }
+ else
+ {
+ matrix[m->m1]|=m->b1;
+
+ if (m->m2!=-1)
+ matrix[m->m2]|=m->b2;
+ }
+ }
+
+ m++;
+ }
}
@@ -134,19 +544,109 @@ Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr)
void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val)
{
+ addr=addr&0x7fff;
+
if (addr>=RAMBOT && addr<=RAMTOP)
- mem[addr&0x7fff]=val;
+ mem[addr]=val;
}
Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port)
{
- return 0;
+ Z80Byte b=0;
+
+ printf("IN %4.4x\n",port);
+
+ switch(port&0xff)
+ {
+ case 0xfe: /* ULA */
+ /* Key matrix
+ */
+ switch(port&0xff00)
+ {
+ case 0xfe00:
+ b=matrix[0];
+ break;
+ case 0xfd00:
+ b=matrix[1];
+ break;
+ case 0xfb00:
+ b=matrix[2];
+ break;
+ case 0xf700:
+ b=matrix[3];
+ break;
+ case 0xef00:
+ b=matrix[4];
+ break;
+ case 0xdf00:
+ b=matrix[5];
+ break;
+ case 0xbf00:
+ b=matrix[6];
+ break;
+ case 0x7f00:
+ b=matrix[7];
+ break;
+ }
+
+ /* Turn off HSYNC if NMI generator is OFF and redraw screen to
+ match output ULA has since sent out.
+ */
+ if (!nmigen && hsync)
+ {
+ hsync=FALSE;
+
+ GFXEndFrame(TRUE);
+ GFXClear(white);
+
+ ULA.x=0;
+ ULA.y=-1;
+ ULA.c=7;
+ ULA.release=FALSE;
+
+ GFXStartFrame();
+ }
+ else
+ {
+ /* Reset and hold ULA counter
+ */
+ ULA.c=0;
+ ULA.release=FALSE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return b;
}
void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val)
{
+ printf("OUT %4.4x\n",port);
+
+ /* Any port write releases the ULA line counter
+ */
+ ULA.release=TRUE;
+
+ switch(port&0xff)
+ {
+ case 0xfd: /* NMI generator OFF */
+ nmigen=FALSE;
+ break;
+
+ case 0xfe: /* NMI generator ON */
+ nmigen=TRUE;
+ break;
+
+ case 0xff: /* HSYNC generator ON */
+ hsync=TRUE;
+ Z80ResetCycles(z80,0);
+ break;
+ }
}
@@ -156,4 +656,16 @@ Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr)
}
+const char *ZX81Info(Z80 *z80)
+{
+ static char buff[80];
+
+ sprintf(buff,"NMIGEN: %s HSYNC: %s",
+ nmigen ? "ON":"OFF",
+ hsync ? "ON":"OFF");
+
+ return buff;
+}
+
+
/* END OF FILE */
diff --git a/src/zx81.h b/src/zx81.h
index 7fa865d..037363f 100644
--- a/src/zx81.h
+++ b/src/zx81.h
@@ -28,11 +28,16 @@
#define EZX81ZX81H "$Id$"
#include "z80.h"
+#include "SDL.h"
/* Initialise the ZX81
*/
-void ZX81Init(void);
+void ZX81Init(Z80 *z80);
+
+/* Handle keypresses
+*/
+void ZX81KeyEvent(SDL_Event *e);
/* Interfaces for the Z80
*/
@@ -42,6 +47,10 @@ Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port);
void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val);
Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr);
+/* Interfaces for memory menu
+*/
+const char *ZX81Info(Z80 *z80);
+
#endif