diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 200 | ||||
-rw-r--r-- | src/config.c | 176 | ||||
-rw-r--r-- | src/config.h | 70 | ||||
-rw-r--r-- | src/exit.c | 56 | ||||
-rw-r--r-- | src/exit.h | 39 | ||||
-rw-r--r-- | src/font.h | 1101 | ||||
-rw-r--r-- | src/gfx.c | 395 | ||||
-rw-r--r-- | src/gfx.h | 143 | ||||
-rw-r--r-- | src/gui.c | 210 | ||||
-rw-r--r-- | src/gui.h | 50 | ||||
-rw-r--r-- | src/main.c | 138 | ||||
-rw-r--r-- | src/memmenu.c | 329 | ||||
-rw-r--r-- | src/memmenu.h | 46 | ||||
-rw-r--r-- | src/spec.c | 673 | ||||
-rw-r--r-- | src/spec.h | 58 |
15 files changed, 3684 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..ed3c38e --- /dev/null +++ b/src/Makefile @@ -0,0 +1,200 @@ +# espec - ZX 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 +# +# ------------------------------------------------------------------------- +# +# $Id: Makefile,v 1.1.1.1 2003-12-23 23:33:02 ianc Exp $ +# + + +# This CFLAGS assumes that gcc is being used. +# Simply comment out if not, and replace as needed. +# Other CFLAGS lines *are* required. +# +CFLAGS = -g -Wall -Werror -pedantic -ansi + +TARGET = espec + +Z80LIB = z80/z80.a + +SOURCE = main.c \ + spec.c \ + config.c \ + gfx.c \ + gui.c \ + memmenu.c \ + exit.c + +OBJECTS = main.o \ + spec.o \ + config.o \ + gfx.o \ + gui.o \ + memmenu.o \ + exit.o + +CFLAGS += -Iz80 `sdl-config --cflags` + +LIBS = $(Z80LIB) `sdl-config --libs` + + +$(TARGET): $(OBJECTS) $(Z80LIB) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) + +$(Z80LIB): z80/*.[ch] + cd z80; make ; cd .. + +clean: + rm -f $(TARGET) $(OBJECTS) core + cd z80; make clean; cd .. + +depend: + makedepend -- $(CFLAGS) -- $(SOURCE) + if test -e Makefile ; then rm -f Makefile.bak ; fi + 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 gfx.h gui.h memmenu.h config.h +main.o: exit.h +spec.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h +spec.o: /usr/include/sys/_types.h /usr/include/machine/_types.h +spec.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h +spec.o: gfx.h /usr/local/include/SDL/SDL.h /usr/local/include/SDL/SDL_main.h +spec.o: /usr/local/include/SDL/SDL_types.h +spec.o: /usr/local/include/SDL/SDL_getenv.h +spec.o: /usr/local/include/SDL/SDL_error.h +spec.o: /usr/local/include/SDL/begin_code.h +spec.o: /usr/local/include/SDL/close_code.h +spec.o: /usr/local/include/SDL/SDL_rwops.h /usr/local/include/SDL/SDL_timer.h +spec.o: /usr/local/include/SDL/SDL_audio.h +spec.o: /usr/local/include/SDL/SDL_byteorder.h +spec.o: /usr/local/include/SDL/SDL_cdrom.h +spec.o: /usr/local/include/SDL/SDL_joystick.h +spec.o: /usr/local/include/SDL/SDL_events.h +spec.o: /usr/local/include/SDL/SDL_active.h +spec.o: /usr/local/include/SDL/SDL_keyboard.h +spec.o: /usr/local/include/SDL/SDL_keysym.h +spec.o: /usr/local/include/SDL/SDL_mouse.h /usr/local/include/SDL/SDL_video.h +spec.o: /usr/local/include/SDL/SDL_mutex.h /usr/local/include/SDL/SDL_quit.h +spec.o: /usr/local/include/SDL/SDL_version.h gui.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 /usr/include/ctype.h /usr/include/runetype.h +gui.o: gui.h /usr/local/include/SDL/SDL.h /usr/local/include/SDL/SDL_main.h +gui.o: /usr/local/include/SDL/SDL_types.h /usr/local/include/SDL/SDL_getenv.h +gui.o: /usr/local/include/SDL/SDL_error.h /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 +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 gfx.h +memmenu.o: /usr/local/include/SDL/SDL.h /usr/local/include/SDL/SDL_main.h +memmenu.o: /usr/local/include/SDL/SDL_types.h +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_timer.h +memmenu.o: /usr/local/include/SDL/SDL_audio.h +memmenu.o: /usr/local/include/SDL/SDL_byteorder.h +memmenu.o: /usr/local/include/SDL/SDL_cdrom.h +memmenu.o: /usr/local/include/SDL/SDL_joystick.h +memmenu.o: /usr/local/include/SDL/SDL_events.h +memmenu.o: /usr/local/include/SDL/SDL_active.h +memmenu.o: /usr/local/include/SDL/SDL_keyboard.h +memmenu.o: /usr/local/include/SDL/SDL_keysym.h +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 gui.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 diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..4035d22 --- /dev/null +++ b/src/config.c @@ -0,0 +1,176 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Config file + +*/ +static const char ident[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "exit.h" +#include "config.h" + +static const char ident_h[]=ESPEC_CONFIG_H; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- CONFIG +*/ +static char rompath[FILENAME_MAX]="./zx81.rom"; +static char tapedir[FILENAME_MAX]="."; +static int fullscreen=FALSE; +static int memsize=16; +static int frames=50; +static int scale=1; +static int trace=0; + +static const struct +{ + const char *name; + void *var; + int is_int; +} config[]= { + {"rompath", rompath, FALSE}, + {"tapedir", tapedir, FALSE}, + {"fullscreen", &fullscreen, TRUE}, + {"memsize", &memsize, TRUE}, + {"frames", &frames, TRUE}, + {"scale", &scale, TRUE}, + {"trace", &trace, TRUE}, + {NULL, NULL, FALSE} + }; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void Parse(FILE *fp) +{ + char buff[1024]; + + while(fgets(buff,sizeof buff,fp)) + { + size_t l; + + l=strlen(buff); + + if (buff[l-1]=='\n') + buff[--l]=0; + + if (l>0 && buff[0]!='#') + { + char *t1=NULL; + char *t2=NULL; + + t1=strtok(buff,"\t"); + t2=strtok(NULL,"\t"); + + if (t2) + { + int f; + + for(f=0;config[f].name;f++) + { + if (strcmp(config[f].name,t1)==0) + { + if (config[f].is_int) + { + int *i; + + i=config[f].var; + *i=atoi(t2); + } + else + { + char *p; + + p=config[f].var; + strcpy(p,t2); + } + } + } + } + else + { + fprintf(stderr,"Ignored bad config: %s %s\n",t1,t2 ? t2:""); + } + } + } +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void ConfigRead(void) +{ + FILE *fp; + char path[FILENAME_MAX]={0}; + + if (getenv("HOME")) + strcpy(path,getenv("HOME")); + + strcat(path,"/.ezx81"); + + if ((fp=fopen(path,"r"))) + { + Parse(fp); + fclose(fp); + } +} + + +int IConfig(IConfigVar v) +{ + static const int *vars[]= + { + &fullscreen, + &memsize, + &frames, + &scale, + &trace + }; + + return *vars[v]; +} + + +const char *SConfig(SConfigVar v) +{ + static const char *vars[]= + { + rompath, + tapedir + }; + + return vars[v]; +} + + +/* END OF FILE */ diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..94dad15 --- /dev/null +++ b/src/config.h @@ -0,0 +1,70 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Config file + +*/ + +#ifndef ESPEC_CONFIG_H +#define ESPEC_CONFIG_H "$Id$" + + +/* Integer settings +*/ +typedef enum +{ + CONF_FULLSCREEN, + CONF_MEMSIZE, + CONF_FRAMES_PER_SEC, + CONF_SCALE, + CONF_TRACE +} IConfigVar; + + +/* String settings +*/ +typedef enum +{ + CONF_ROMFILE, + CONF_TAPEDIR +} SConfigVar; + + +/* Read config file +*/ +void ConfigRead(void); + + +/* Get integer setting +*/ +int IConfig(IConfigVar v); + + +/* Get string setting +*/ +const char *SConfig(SConfigVar v); + + +#endif + + +/* END OF FILE */ diff --git a/src/exit.c b/src/exit.c new file mode 100644 index 0000000..254acc3 --- /dev/null +++ b/src/exit.c @@ -0,0 +1,56 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides a common error exit point + +*/ +static const char ident[]="$Id$"; + +#include <stdlib.h> +#include <stdarg.h> +#include "exit.h" + +#include <SDL.h> + +static const char ident_h[]=ESPEC_EXIT_H; + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void Exit(const char *format,...) +{ + va_list va; + + if (SDL_WasInit(SDL_INIT_EVERYTHING)) + { + SDL_Quit(); + } + + va_start(va,format); + vfprintf(stderr,format,va); + va_end(va); + + exit(EXIT_FAILURE); +} + + +/* END OF FILE */ diff --git a/src/exit.h b/src/exit.h new file mode 100644 index 0000000..084fc78 --- /dev/null +++ b/src/exit.h @@ -0,0 +1,39 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides a common error exit point + +*/ + +#ifndef ESPEC_EXIT_H +#define ESPEC_EXIT_H "$Id$" + + +/* Exit +*/ +void Exit(const char *format,...); + + +#endif + + +/* END OF FILE */ diff --git a/src/font.h b/src/font.h new file mode 100644 index 0000000..f4a6925 --- /dev/null +++ b/src/font.h @@ -0,0 +1,1101 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Internal font for gfx routines + +*/ + +#ifndef ESPEC_FONT_H +#define ESPEC_FONT_H "$Id$" + +typedef unsigned char FontChar[64]; + +#define NULLCHARDEF {0} + + +static const FontChar font[128]= +{ + NULLCHARDEF, /* 00 */ + + { /* 01 FONT_UP_ARROW */ + 0,0,0,1,1,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,1,1,1,1,1,0, + 1,1,0,1,1,0,1,1, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + }, + { /* 02 FONT_DOWN_ARROW */ + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 1,1,0,1,1,0,1,1, + 0,1,1,1,1,1,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,1,1,0,0,0, + }, + { /* 03 FONT_LEFT_ARROW */ + 0,0,0,1,0,0,0,0, + 0,0,1,1,0,0,0,0, + 0,1,1,0,0,0,0,0, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 0,1,1,0,0,0,0,0, + 0,0,1,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + }, + { /* 04 FONT_RIGHT_ARROW */ + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,1,0,0, + 0,0,0,0,0,1,1,0, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 0,0,0,0,0,1,1,0, + 0,0,0,0,1,1,0,0, + 0,0,0,0,1,0,0,0, + }, + { /* 05 FONT_TICK */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,1,1, + 0,0,0,0,0,1,1,0, + 1,1,0,0,1,1,0,0, + 0,1,1,1,1,0,0,0, + 0,0,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 06 FONT_CROSS */ + 0,0,0,0,0,0,0,0, + 0,1,1,0,0,0,1,1, + 0,0,1,1,0,1,1,0, + 0,0,0,1,1,1,0,0, + 0,0,0,1,1,1,0,0, + 0,0,1,1,0,1,1,0, + 0,1,1,0,0,0,1,1, + 0,0,0,0,0,0,0,0, + }, + { /* 07 FONT_CURSOR */ + 1,1,1,1,1,1,1,1, + 1,0,1,1,1,1,1,1, + 1,0,1,1,1,1,1,1, + 1,0,1,1,1,1,1,1, + 1,0,1,1,1,1,1,1, + 1,0,1,1,1,1,1,1, + 1,0,0,0,0,0,0,1, + 1,1,1,1,1,1,1,1, + }, + { /* 08 FONT_COPYRIGHT */ + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 1,0,0,1,1,0,0,1, + 1,0,1,0,0,0,0,1, + 1,0,1,0,0,0,0,1, + 1,0,0,1,1,0,0,1, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + }, + + NULLCHARDEF, /* 09 */ + NULLCHARDEF, /* 0a */ + NULLCHARDEF, /* 0b */ + NULLCHARDEF, /* 0c */ + NULLCHARDEF, /* 0d */ + NULLCHARDEF, /* 0e */ + NULLCHARDEF, /* 0f */ + NULLCHARDEF, /* 10 */ + NULLCHARDEF, /* 11 */ + NULLCHARDEF, /* 12 */ + NULLCHARDEF, /* 13 */ + NULLCHARDEF, /* 14 */ + NULLCHARDEF, /* 15 */ + NULLCHARDEF, /* 16 */ + NULLCHARDEF, /* 17 */ + NULLCHARDEF, /* 18 */ + NULLCHARDEF, /* 19 */ + NULLCHARDEF, /* 1a */ + NULLCHARDEF, /* 1b */ + NULLCHARDEF, /* 1c */ + NULLCHARDEF, /* 1d */ + NULLCHARDEF, /* 1e */ + NULLCHARDEF, /* 1f */ + + { /* 20 ' ' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 21 '!' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 22 '"' */ + 0,0,0,0,0,0,0,0, + 0,0,1,0,0,1,0,0, + 0,0,1,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 23 '#' */ + 0,0,0,0,0,0,0,0, + 0,0,1,0,0,1,0,0, + 0,1,1,1,1,1,1,0, + 0,0,1,0,0,1,0,0, + 0,0,1,0,0,1,0,0, + 0,1,1,1,1,1,1,0, + 0,0,1,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 24 '$' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,1,0,1,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,1,0,1,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,1,0,0,0, + }, + { /* 25 '%' */ + 0,0,0,0,0,0,0,0, + 0,1,1,0,0,0,1,0, + 0,1,1,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,0,1,1,0, + 0,1,0,0,0,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 26 '&' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,1,0,1,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 27 ''' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 28 '(' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 29 ')' */ + 0,0,0,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 2a '*' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 2b '+' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 2c ',' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + }, + { /* 2d '-' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 2e '.' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 2f '/' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 30 '0' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,1,1,0, + 0,1,0,0,1,0,1,0, + 0,1,0,1,0,0,1,0, + 0,1,1,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 31 '1' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 32 '2' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 33 '3' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,1,1,0,0, + 0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 34 '4' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,1,0,1,0,0,0, + 0,1,0,0,1,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 35 '5' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 36 '6' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 37 '7' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,0,1,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 38 '8' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 39 '9' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 3a ':' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 3b ';' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,0,0,0,0, + }, + { /* 3c '<' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 3d '=' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 3e '>' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 3f '?' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 40 '@' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,1,0,1,0, + 0,1,0,1,0,1,1,0, + 0,1,0,1,1,1,1,0, + 0,1,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 41 'A' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,1,1,1,1,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 42 'B' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 43 'C' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 44 'D' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,1,0,0, + 0,1,1,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 45 'E' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 46 'F' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 47 'G' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,1,1,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 48 'H' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,1,1,1,1,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 49 'I' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 4a 'J' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0, + 0,0,0,0,0,0,1,0, + 0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 4b 'K' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,1,0,0,0, + 0,1,1,1,0,0,0,0, + 0,1,0,0,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 4c 'L' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 4d 'M' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,1,1,0,0,1,1,0, + 0,1,0,1,1,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 4e 'N' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,1,1,0,0,0,1,0, + 0,1,0,1,0,0,1,0, + 0,1,0,0,1,0,1,0, + 0,1,0,0,0,1,1,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 4f 'O' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 50 'P' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 51 'Q' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,1,0,0,1,0, + 0,1,0,0,1,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 52 'R' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 53 'S' */ + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 54 'T' */ + 0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 55 'U' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 56 'V' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,0,1,0,0,1,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 57 'W' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,0,0,0,1,0, + 0,1,0,1,1,0,1,0, + 0,0,1,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 58 'X' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,1,0, + 0,0,1,0,0,1,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,1,0,0,1,0,0, + 0,1,0,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 59 'Y' */ + 0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,1,0, + 0,1,0,0,0,1,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 5a 'Z' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 5b '[' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,1,1,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 5c '\' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 5d ']' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,1,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 5e '^' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,1,0,1,0,1,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 5f '_' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1, + }, + { /* 60 '`' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,1,1,0,0, + 0,0,1,0,0,0,1,0, + 0,1,1,1,1,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,1,1,1,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 61 'a' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 62 'b' */ + 0,0,0,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,0,1,0,0,0,1,0, + 0,0,1,0,0,0,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 63 'c' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,1,1,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,0,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 64 'd' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 65 'e' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,1,1,1,0,0,0, + 0,1,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 66 'f' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,1,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 67 'g' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,1,0,0, + 0,0,1,1,1,0,0,0, + }, + { /* 68 'h' */ + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,1,1,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 69 'i' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 6a 'j' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,1,0,0, + 0,0,1,0,0,1,0,0, + 0,0,0,1,1,0,0,0, + }, + { /* 6b 'k' */ + 0,0,0,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,1,0,0,0, + 0,0,1,1,0,0,0,0, + 0,0,1,1,0,0,0,0, + 0,0,1,0,1,0,0,0, + 0,0,1,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 6c 'l' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 6d 'm' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,1,0,1,0,0,0, + 0,1,0,1,0,1,0,0, + 0,1,0,1,0,1,0,0, + 0,1,0,1,0,1,0,0, + 0,1,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 6e 'n' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 6f 'o' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 70 'p' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,1,1,1,0,0,0, + 0,1,0,0,0,0,0,0, + 0,1,0,0,0,0,0,0, + }, + { /* 71 'q' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,1,0,0, + 0,0,0,0,0,1,1,0, + }, + { /* 72 'r' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,1,1,1,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 73 's' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,1,0,0,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,0,0,0,0,1,0,0, + 0,1,1,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 74 't' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,1,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 75 'u' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 76 'v' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,0,1,0,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 77 'w' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,1,0,1,0,0, + 0,1,0,1,0,1,0,0, + 0,1,0,1,0,1,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 78 'x' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,1,0,0,0, + 0,1,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 79 'y' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,0,1,1,1,1,0,0, + 0,0,0,0,0,1,0,0, + 0,0,1,1,1,0,0,0, + }, + { /* 7a 'z' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,1,0,0,0,0,0, + 0,1,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 7b '{' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,1,1,0, + 0,0,0,0,1,0,0,0, + 0,0,1,1,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,1,1,0, + 0,0,0,0,0,0,0,0, + }, + { /* 7c '|' */ + 0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 7d '}' */ + 0,0,0,0,0,0,0,0, + 0,1,1,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,0,1,1,0,0, + 0,0,0,1,0,0,0,0, + 0,0,0,1,0,0,0,0, + 0,1,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + { /* 7e '~' */ + 0,0,0,0,0,0,0,0, + 0,0,0,1,0,1,0,0, + 0,0,1,0,1,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + }, + NULLCHARDEF, /* 7f */ +}; + + +#endif + + +/* END OF FILE */ diff --git a/src/gfx.c b/src/gfx.c new file mode 100644 index 0000000..a77c496 --- /dev/null +++ b/src/gfx.c @@ -0,0 +1,395 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Wrapper to SDL + +*/ +static const char ident[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include "gfx.h" +#include "exit.h" +#include "config.h" + +#include "font.h" + +static const char ident_h[]=ESPEC_GFX_H; +static const char ident_fh[]=ESPEC_FONT_H; + + +/* ---------------------------------------- MACROS +*/ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define SCR_W 320 +#define SCR_H 200 + +#define LOCK do \ + { \ + if (SDL_MUSTLOCK(surface)) \ + if (SDL_LockSurface(surface)<0) \ + Exit("Failed to lock surface: %s\n", \ + SDL_GetError()); \ + } while(0) + +#define UNLOCK do \ + { \ + if (SDL_MUSTLOCK(surface)) \ + SDL_UnlockSurface(surface); \ + } while(0) + + +/* ---------------------------------------- STATICS +*/ +static SDL_Surface *surface; +static Uint32 ticks; +static Uint32 frame; +static int scale; + +static void (*putpixel)(int x, int y, Uint32 col); + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ + +/* Taken from SDL documentation +*/ +static void normal_putpixel(int x, int y, Uint32 pixel) +{ + int bpp; + Uint8 *p; + + bpp=surface->format->BytesPerPixel; + p=(Uint8 *)surface->pixels+y*surface->pitch+x*bpp; + + switch(bpp) + { + case 1: + *p=pixel; + break; + + case 2: + *(Uint16 *)p=pixel; + break; + + case 3: + if(SDL_BYTEORDER==SDL_BIG_ENDIAN) + { + p[0]=(pixel>>16)&0xff; + p[1]=(pixel>>8)&0xff; + p[2]=pixel&0xff; + } else + { + p[0]=pixel&0xff; + p[1]=(pixel>>8)&0xff; + p[2]=(pixel>>16)&0xff; + } + break; + + case 4: + *(Uint32 *)p=pixel; + break; + } +} + + +static void scale_putpixel(int x, int y, Uint32 pixel) +{ + int sx,sy; + + x*=scale; + y*=scale; + + for(sx=0;sx<scale;sx++) + for(sy=0;sy<scale;sy++) + normal_putpixel(x+sx,y+sy,pixel); +} + + +static void DoHLine(int x1, int x2, int y, Uint32 col) +{ + for(;x1<=x2;x1++) + putpixel(x1,y,col); +} + + +static void DoVLine(int x, int y1, int y2, Uint32 col) +{ + for(;y1<=y2;y1++) + putpixel(x,y1,col); +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void GFXInit(void) +{ + if (IConfig(CONF_FULLSCREEN)) + scale=1; + else + scale=IConfig(CONF_SCALE); + + if (scale<0) + scale=1; + + if (scale>1) + putpixel=scale_putpixel; + else + putpixel=normal_putpixel; + + frame=1000/IConfig(CONF_FRAMES_PER_SEC); + + 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, + 0, + IConfig(CONF_FULLSCREEN) ? + SDL_FULLSCREEN : 0))) + { + Exit("Failed to open video: %s\n",SDL_GetError()); + } + + SDL_ShowCursor(SDL_DISABLE); + SDL_WM_SetCaption("eSPEC","eSPEC"); +} + + +SDL_Surface *GFXGetSurface(void) +{ + return surface; +} + + +Uint32 GFXRGB(Uint8 r, Uint8 g, Uint8 b) +{ + return SDL_MapRGB(surface->format,r,g,b); +} + + +void GFXClear(Uint32 col) +{ + SDL_FillRect(surface,NULL,col); +} + + +void GFXStartFrame(void) +{ + ticks=SDL_GetTicks(); +} + + +void GFXEndFrame(int delay) +{ + SDL_UpdateRect(surface,0,0,0,0); + + if (delay) + { + Uint32 diff; + + diff=SDL_GetTicks()-ticks; + + if (diff<frame) + SDL_Delay(frame-diff); + } +} + + +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; + + while(SDL_PollEvent(&e)) + { + if (e.type==SDL_KEYUP || e.type==SDL_KEYDOWN) + return &e; + } + + return NULL; +} + + +SDL_Event *GFXWaitKey(void) +{ + static SDL_Event e; + + do + { + SDL_WaitEvent(&e); + } while (e.type!=SDL_KEYDOWN); + + return &e; +} + + +void GFXPlot(int x, int y, Uint32 col) +{ + LOCK; + + putpixel(x,y,col); + + UNLOCK; +} + + +void GFXRect(int x, int y, int w, int h, Uint32 col, int solid) +{ + LOCK; + + if (solid) + { + SDL_Rect r; + + r.x=x*scale; + r.y=y*scale; + r.w=w*scale; + r.h=h*scale; + + SDL_FillRect(surface,&r,col); + } + else + { + DoHLine(x,x+w-1,y,col); + DoHLine(x,x+w-1,y+h-1,col); + DoVLine(x,y,y+h-1,col); + DoVLine(x+w-1,y,y+h-1,col); + } + + UNLOCK; +} + + +void GFXHLine(int x1, int x2, int y, Uint32 col) +{ + LOCK; + DoHLine(x1,x2,y,col); + UNLOCK; +} + + +void GFXVLine(int x, int y1, int y2, Uint32 col) +{ + LOCK; + DoVLine(x,y1,y2,col); + UNLOCK; +} + + +void GFXPrint(int x, int y, Uint32 col, 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); + } + } + } + + p++; + x+=8; + } + + UNLOCK; +} + + +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 new file mode 100644 index 0000000..baa19d2 --- /dev/null +++ b/src/gfx.h @@ -0,0 +1,143 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Wrapper to SDL + +*/ + +#ifndef ESPEC_GFX_H +#define ESPEC_GFX_H "$Id$" + +#include "SDL.h" + + +/* ---------------------------------------- CONSTANTS +*/ +#define FONT_UP_ARROW '\001' +#define FONT_DOWN_ARROW '\002' +#define FONT_LEFT_ARROW '\003' +#define FONT_RIGHT_ARROW '\004' +#define FONT_TICK '\005' +#define FONT_CROSS '\006' +#define FONT_CURSOR '\007' +#define FONT_COPYRIGHT '\010' + + +/* ---------------------------------------- INTERFACES +*/ + +/* Initialise +*/ +void GFXInit(void); + + +/* Get the SDL_Surface for the screen +*/ +SDL_Surface *GFXGetSurface(void); + + +/* Get the pixel value for a colour +*/ +Uint32 GFXRGB(Uint8 r, Uint8 g, Uint8 b); + + +/* Clear the screen +*/ +void GFXClear(Uint32 col); + + +/* Indicate a frame is starting +*/ +void GFXStartFrame(void); + + +/* Indicate a frame is done and refreshes the screen + If delay is TRUE, sleeps to implement the frames_per_sec config. + It's safe to call this multiple times without a matching GFXStartFrame(). +*/ +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); + + +/* Wait for a keypress (key up event) +*/ +SDL_Event *GFXWaitKey(void); + + +/* + Note that no bound checking (except for GFXPrint()) is done - it is the + callers responsibility to plot onscreen. +*/ + +/* Plot a point +*/ +void GFXPlot(int x, int y, Uint32 col); + + +/* Draw a rectangle +*/ +void GFXRect(int x, int y, int w, int h, Uint32 col, int solid); + + +/* Draw an horizontal line +*/ +void GFXHLine(int x1, int x2, int y, Uint32 col); + + +/* Draw a vertical line +*/ +void GFXVLine(int x, int y1, int y2, Uint32 col); + + +/* Draws text using an internal 8x8 monspaced font. The only supported + characters are 32-126 and the special FONT_xxx characters defined + above. The routine assumes the environment operates with ASCII. + + The co-ord given is the top left of the first character, and characters + are drawn transparently. + + Causes undefined behaviour if the generated string from the printf + format is longer than 256 characters. +*/ +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 + + +/* END OF FILE */ diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..3a4b031 --- /dev/null +++ b/src/gui.c @@ -0,0 +1,210 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Basic GUI routines + +*/ +static const char ident[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> + +#include "gui.h" +#include "gfx.h" +#include "exit.h" + +static const char ident_h[]=ESPEC_GUI_H; + + +/* ---------------------------------------- MACROS +*/ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* Must match gfx.c +*/ +#define SCR_W 320 +#define SCR_H 200 + +/* ---------------------------------------- STATICS +*/ + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void *Malloc(size_t size) +{ + void *p=malloc(size); + + if (!p) + Exit("malloc failed for %lu bytes\n",(unsigned long)size); + + return p; +} + + +static void Centre(const char *p, int y, int r, int g, int b) +{ + GFXPrint((SCR_W-strlen(p)*8)/2,y,GFXRGB(r,g,b),"%s",p); +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void GUIMessage(const char *title, const char *format,...) +{ + char buff[1025]; + va_list va; + char *p; + int no; + int f; + char **line; + int width; + int height; + int x,y; + + va_start(va,format); + vsprintf(buff,format,va); + va_end(va); + + p=buff; + no=1; + + while(*p) + { + if (*p=='\n') + no++; + + p++; + } + + line=Malloc(sizeof *line * no); + + line[0]=strtok(buff,"\n"); + width=strlen(line[0]); + + for(f=1;f<no;f++) + { + line[f]=strtok(NULL,"\n"); + + 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; + + if (height>(SCR_H-10)) + height=SCR_H-10; + + y=(SCR_H-height)/2; + x=(SCR_W-width)/2; + + GFXRect(x-1,y-1, + width+2,height+2, + GFXRGB(255,255,255),FALSE); + + GFXRect(x,y, + width,height, + GFXRGB(0,0,0),TRUE); + + Centre(title,y+2,255,255,255); + GFXHLine(x+2,x+width-4,y+10,GFXRGB(255,255,255)); + + for(f=0;f<no;f++) + Centre(line[f],y+5+10*(f+1),200,200,200); + + Centre("Press a key",y+height-10,255,0,0); + + GFXEndFrame(FALSE); + + GFXWaitKey(); + + free(line); +} + + +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 new file mode 100644 index 0000000..6d2fcb9 --- /dev/null +++ b/src/gui.h @@ -0,0 +1,50 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Basic GUI routines + +*/ + +#ifndef ESPEC_GUI_H +#define ESPEC_GUI_H "$Id$" + +#include "SDL.h" + + +/* ---------------------------------------- INTERFACES +*/ + +/* 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,...); + + +/* Enter a string, max 40 characters +*/ +const char *GUIInputString(const char *prompt, const char *orig); + + +#endif + + +/* END OF FILE */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e69eb77 --- /dev/null +++ b/src/main.c @@ -0,0 +1,138 @@ +/* + + 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 + + ------------------------------------------------------------------------- + +*/ +static const char id[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> + +#include "SDL.h" + +#include "z80.h" +#include "spec.h" +#include "gfx.h" +#include "gui.h" +#include "memmenu.h" +#include "config.h" +#include "exit.h" + + +/* ---------------------------------------- MACROS +*/ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- STATICS +*/ +static Uint32 white; +static Uint32 black; +static Uint32 grey; + + +/* ---------------------------------------- PROTOS +*/ + + +/* ---------------------------------------- MAIN +*/ +int main(int argc, char *argv[]) +{ + Z80 *z80; + SDL_Event *e; + int quit; + int trace; + + ConfigRead(); + + trace=IConfig(CONF_TRACE); + + z80=Z80Init(SPECWriteMem, + SPECReadMem, + SPECWritePort, + SPECReadPort, + SPECReadForDisassem, + NULL); + + GFXInit(); + + SPECInit(z80); + + white=GFXRGB(255,255,255); + grey=GFXRGB(128,128,128); + black=GFXRGB(0,0,0); + + quit=FALSE; + + while(!quit) + { + 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: + SPECKeyEvent(e); + break; + } + } + } + + 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..2badf65 --- /dev/null +++ b/src/memmenu.c @@ -0,0 +1,329 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides a common error exit point + +*/ +static const char ident[]="$Id$"; + +#include <stdlib.h> +#include <string.h> + +#include "memmenu.h" +#include "spec.h" +#include "gfx.h" +#include "gui.h" + +#include <SDL.h> + +static const char ident_h[]=ESPEC_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)SPECReadForDisassem(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",SPECInfo(z80)); + y+=8; +} + + + + +/* END OF FILE */ diff --git a/src/memmenu.h b/src/memmenu.h new file mode 100644 index 0000000..524069f --- /dev/null +++ b/src/memmenu.h @@ -0,0 +1,46 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides a menu driven interface for analysing memory + +*/ + +#ifndef ESPEC_MEMMENU_H +#define ESPEC_MEMMENU_H "$Id$" + +#include "z80.h" + + +/* Memory menu +*/ +void MemoryMenu(Z80 *z80); + + +/* Display the state of the SPEC at the bottom of the screen +*/ +void DisplayState(Z80 *z80); + + +#endif + + +/* END OF FILE */ diff --git a/src/spec.c b/src/spec.c new file mode 100644 index 0000000..51006df --- /dev/null +++ b/src/spec.c @@ -0,0 +1,673 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides the emulation for the SPEC + +*/ +static const char ident[]="$Id$"; + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "spec.h" +#include "gfx.h" +#include "gui.h" +#include "config.h" +#include "exit.h" + +static const char ident_h[]=ESPEC_SPECH; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- STATICS +*/ +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 SPEC 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; +static const int OFF_Y=(200-192)/2; + +static Z80Byte mem[0x10000]; + +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 +*/ +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); + printf("NMIGEN\n"); + } + else if (hsync) + { + printf("HSYNC\n"); + if (ULA.release) + { + /* ULA.release=FALSE; */ + ULA.c=(ULA.c+1)&7; + ULA.y++; + ULA.x=0; + } + } + } + + return TRUE; +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void SPECInit(Z80 *z80) +{ + FILE *fp; + Z80Word f; + + if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb"))) + { + GUIMessage("ERROR","Failed to open SPEC 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); + Exit(""); + } + + /* Patch the ROM + */ + RomPatch(); + Z80LodgeCallback(z80,Z80_EDHook,EDCallback); + Z80LodgeCallback(z80,Z80_Fetch,CheckTimers); + + /* Mirror the ROM + */ + memcpy(mem+ROMLEN,mem,ROMLEN); + + RAMBOT=0x4000; + + /* Memory size (1 or 16K) + */ + if (IConfig(CONF_MEMSIZE)==16) + RAMLEN=0x2000; + else + RAMLEN=0x400; + + RAMTOP=RAMBOT+RAMLEN; + + 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 SPECKeyEvent(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++; + } +} + + +Z80Byte SPECReadMem(Z80 *z80, Z80Word addr) +{ + /* Memory reads above 32K invoke the ULA + */ + if (addr>0x7fff) + { + Z80Byte b; + + /* B6 of R is tied to the IRQ line (only when HSYNC active?) + if ((HSYNC)&&(!(z80->R&0x40))) + z80->IRQ=TRUE; + */ + + b=mem[addr&0x7fff]; + + /* If bit 6 of the opcode is set the opcode is sent as is to the + Z80. If it's not, the byte is interretted by the ULA. + */ + if (b&0x40) + { + ULA_Video_Shifter(z80,0); + } + else + { + ULA_Video_Shifter(z80,b); + b=0; + } + + return b; + } + else + return mem[addr&0x7fff]; + +} + + +void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val) +{ + addr=addr&0x7fff; + + if (addr>=RAMBOT && addr<=RAMTOP) + mem[addr]=val; +} + + +Z80Byte SPECReadPort(Z80 *z80, Z80Word port) +{ + 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 SPECWritePort(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; + } +} + + +Z80Byte SPECReadForDisassem(Z80 *z80, Z80Word addr) +{ + return mem[addr&0x7fff]; +} + + +const char *SPECInfo(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/spec.h b/src/spec.h new file mode 100644 index 0000000..611b5a4 --- /dev/null +++ b/src/spec.h @@ -0,0 +1,58 @@ +/* + + 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 + + ------------------------------------------------------------------------- + + Provides the emulation for the SPEC + +*/ + +#ifndef ESPEC_SPECH +#define ESPEC_SPECH "$Id$" + +#include "z80.h" +#include "SDL.h" + + +/* Initialise the SPEC +*/ +void SPECInit(Z80 *z80); + +/* Handle keypresses +*/ +void SPECKeyEvent(SDL_Event *e); + +/* Interfaces for the Z80 +*/ +Z80Byte SPECReadMem(Z80 *z80, Z80Word addr); +void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val); +Z80Byte SPECReadPort(Z80 *z80, Z80Word port); +void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val); +Z80Byte SPECReadForDisassem(Z80 *z80, Z80Word addr); + +/* Interfaces for memory menu +*/ +const char *SPECInfo(Z80 *z80); + + +#endif + + +/* END OF FILE */ |