summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2004-01-06 02:06:37 +0000
committerIan C <ianc@noddybox.co.uk>2004-01-06 02:06:37 +0000
commit25bc35fbadebbf28eed3c89978e435d2df557b42 (patch)
tree74619afa6e82dd4818dd210c20396946a7c1722e
parent63c0f2a2f2819940efde5ff52ab13109809405f9 (diff)
Devel checkin - added util and snap objects and non-working TAP support
-rw-r--r--src/Makefile30
-rw-r--r--src/gui.c14
-rw-r--r--src/gui.h27
-rw-r--r--src/main.c54
-rw-r--r--src/memmenu.c40
-rw-r--r--src/snap.c200
-rw-r--r--src/snap.h73
-rw-r--r--src/spec.c100
-rw-r--r--src/spec.h9
-rw-r--r--src/util.c100
-rw-r--r--src/util.h61
11 files changed, 661 insertions, 47 deletions
diff --git a/src/Makefile b/src/Makefile
index 79b1d6a..68ecd6d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -18,7 +18,7 @@
#
# -------------------------------------------------------------------------
#
-# $Id: Makefile,v 1.4 2004-01-05 01:07:07 ianc Exp $
+# $Id: Makefile,v 1.5 2004-01-06 02:06:36 ianc Exp $
#
@@ -34,18 +34,22 @@ Z80LIB = z80/z80.a
SOURCE = main.c \
spec.c \
+ snap.c \
config.c \
gfx.c \
gui.c \
memmenu.c \
+ util.c \
exit.c
OBJECTS = main.o \
spec.o \
+ snap.o \
config.o \
gfx.o \
gui.o \
memmenu.o \
+ util.o \
exit.o
CFLAGS += -Iz80 `sdl-config --cflags`
@@ -72,8 +76,9 @@ depend:
main.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
main.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
-main.o: /usr/include/stdio.h /usr/local/include/SDL/SDL.h
-main.o: /usr/local/include/SDL/SDL_main.h /usr/local/include/SDL/SDL_types.h
+main.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h
+main.o: /usr/local/include/SDL/SDL.h /usr/local/include/SDL/SDL_main.h
+main.o: /usr/local/include/SDL/SDL_types.h
main.o: /usr/local/include/SDL/SDL_getenv.h
main.o: /usr/local/include/SDL/SDL_error.h
main.o: /usr/local/include/SDL/begin_code.h
@@ -111,7 +116,11 @@ 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 gfx.h gui.h config.h exit.h
+spec.o: /usr/local/include/SDL/SDL_version.h snap.h gfx.h gui.h config.h
+spec.o: exit.h
+snap.o: snap.h /usr/include/stdlib.h /usr/include/sys/cdefs.h
+snap.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+snap.o: /usr/include/stdio.h z80/z80.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
@@ -139,9 +148,10 @@ 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: gui.h gfx.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
@@ -153,7 +163,7 @@ gui.o: /usr/local/include/SDL/SDL_keyboard.h
gui.o: /usr/local/include/SDL/SDL_keysym.h /usr/local/include/SDL/SDL_mouse.h
gui.o: /usr/local/include/SDL/SDL_video.h /usr/local/include/SDL/SDL_mutex.h
gui.o: /usr/local/include/SDL/SDL_quit.h /usr/local/include/SDL/SDL_version.h
-gui.o: gfx.h exit.h
+gui.o: 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/stdio.h /usr/include/string.h /usr/include/strings.h
@@ -180,6 +190,10 @@ memmenu.o: /usr/local/include/SDL/SDL_video.h
memmenu.o: /usr/local/include/SDL/SDL_mutex.h
memmenu.o: /usr/local/include/SDL/SDL_quit.h
memmenu.o: /usr/local/include/SDL/SDL_version.h gfx.h gui.h
+util.o: /usr/include/stdio.h /usr/include/sys/cdefs.h
+util.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
+util.o: /usr/include/string.h /usr/include/strings.h util.h
+util.o: /usr/include/stdlib.h exit.h
exit.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h
exit.o: /usr/include/sys/_types.h /usr/include/machine/_types.h
exit.o: /usr/include/stdarg.h exit.h /usr/local/include/SDL/SDL.h
diff --git a/src/gui.c b/src/gui.c
index 3a4b031..5072be1 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -207,4 +207,18 @@ const char *GUIInputString(const char *prompt, const char *orig)
}
+int GUIFileSelect(const char *prompt, int load,
+ const char *start_dir, char path[])
+{
+ /* TODO */
+ if (load)
+ strcpy(path,"/files/emu/spectrum/thrust1.tap");
+ else
+ strcpy(path,"/files/emu/spectrum/testespec.tap");
+
+ strcpy(path,"/files/emu/spectrum/testespec.tap");
+ return TRUE;
+}
+
+
/* END OF FILE */
diff --git a/src/gui.h b/src/gui.h
index 6d2fcb9..953aac9 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -27,8 +27,6 @@
#ifndef ESPEC_GUI_H
#define ESPEC_GUI_H "$Id$"
-#include "SDL.h"
-
/* ---------------------------------------- INTERFACES
*/
@@ -44,6 +42,31 @@ void GUIMessage(const char *title, const char *format,...);
const char *GUIInputString(const char *prompt, const char *orig);
+/* Select a file from the given directory.
+
+ If load is TRUE then a new name cannot be entered.
+
+ Returns TRUE for selected, FALSE for cancelled.
+
+ path holds the new file entered. Note that start_dir can be a path to a
+ file - if chdir(start_dir) would not work, then it is tried with the
+ dirname(1) of start_dir.
+
+ Also start_dir and path can be the same pointer:
+
+ char file[FILENAME_MAX]="/home/foobar/dir/file.tap";
+
+ if (GUI_Fsel("Select tape",TRUE,file,file))
+ ....
+
+ Will work fine.
+*/
+int GUIFileSelect(const char *prompt,
+ int load,
+ const char *start_dir,
+ char path[]);
+
+
#endif
diff --git a/src/main.c b/src/main.c
index 79f0994..e25ce75 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,7 @@ static const char id[]="$Id$";
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include "SDL.h"
@@ -63,6 +64,8 @@ static Uint32 grey;
*/
int main(int argc, char *argv[])
{
+ char tape_in[FILENAME_MAX];
+ char tape_out[FILENAME_MAX];
Z80 *z80;
SDL_Event *e;
int quit;
@@ -72,6 +75,9 @@ int main(int argc, char *argv[])
trace=IConfig(CONF_TRACE);
+ strcpy(tape_in,SConfig(CONF_TAPEDIR));
+ strcpy(tape_out,SConfig(CONF_TAPEDIR));
+
z80=Z80Init(SPECWriteMem,
SPECReadMem,
SPECWritePort,
@@ -89,6 +95,12 @@ int main(int argc, char *argv[])
quit=FALSE;
+ /* Check for initial memory menu usage
+ TODO: Proper switch handling
+ */
+ if (argc>1 && strcmp(argv[1],"-m")==0)
+ MemoryMenu(z80);
+
while(!quit)
{
Z80State s1,s2;
@@ -118,6 +130,48 @@ int main(int argc, char *argv[])
quit=TRUE;
break;
+ case SDLK_F1:
+ if (e->key.state==SDL_PRESSED)
+ GUIMessage("HELP",
+ "ESC - Quit \n"
+ "F1 - Help \n"
+ "F8 - Select tape file for loading\n"
+ "F9 - Select tape file for saving \n"
+ "F10 - Close all open tape files \n"
+ "F11 - Memory Menu \n"
+ "F12 - Toggle onscreen trace ");
+ break;
+
+ case SDLK_F8:
+ if (e->key.state==SDL_PRESSED)
+ {
+ if (GUIFileSelect("TAPE TO LOAD",TRUE,
+ tape_in,tape_in))
+ {
+ SPECMount(SPEC_TAPE_IN,tape_in);
+ }
+ }
+ break;
+
+ case SDLK_F9:
+ if (e->key.state==SDL_PRESSED)
+ {
+ if (GUIFileSelect("TAPE TO SAVE",FALSE,
+ tape_out,tape_out))
+ {
+ SPECMount(SPEC_TAPE_OUT,tape_out);
+ }
+ }
+ break;
+
+ case SDLK_F10:
+ if (e->key.state==SDL_PRESSED)
+ {
+ SPECUnmount(SPEC_TAPE_IN);
+ SPECUnmount(SPEC_TAPE_OUT);
+ }
+ break;
+
case SDLK_F11:
if (e->key.state==SDL_PRESSED)
MemoryMenu(z80);
diff --git a/src/memmenu.c b/src/memmenu.c
index 807e49f..50b9acb 100644
--- a/src/memmenu.c
+++ b/src/memmenu.c
@@ -280,15 +280,15 @@ static void DoDisassem(Z80 *z80, const Z80State *s)
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");
+ "ESC - Exit \n"
+ "H - Disassembly/hex \n"
+ "Enter - Enter address \n"
+ "Up - Prev byte \n"
+ "Down - Next op \n"
+ "Page Up - Back 1 page \n"
+ "Page Down - Forward 1 page \n"
+ "Left - Forward 1024 bytes\n"
+ "Right - Back 1024 bytes ");
break;
case SDLK_ESCAPE:
@@ -437,7 +437,7 @@ static void PlaybackTrace(Z80 *z80)
if (!fp)
{
- GUIMessage("ERROR","Couldn't open tracefile: " TRACE);
+ GUIMessage("ERROR","Couldn't open trace file");
return;
}
@@ -447,7 +447,7 @@ static void PlaybackTrace(Z80 *z80)
if (max_pos==0)
{
- GUIMessage("ERROR","Empty tracefile: " TRACE);
+ GUIMessage("ERROR","Empty trace file");
fclose(fp);
return;
}
@@ -508,15 +508,15 @@ static void PlaybackTrace(Z80 *z80)
case SDLK_F1:
GUIMessage
("PLAYBACK HELP","%s",
- "ESC - Exit\n"
- "Enter - Step number to display\n"
- "P - Search for PC\n"
- "Cursor Up - Prev step\n"
- "Cursor Down - Next step\n"
- "Page Up - Back 50 steps\n"
- "Page Down - Forward 50 steps\n"
- "Cursor Left - Back 1000 steps\n"
- "Cursor Right - Forward 1000 steps\n \n"
+ "ESC - Exit \n"
+ "Enter - Step number \n"
+ "P - Search for PC \n"
+ "Up - Prev step \n"
+ "Down - Next step \n"
+ "Page Up - Back 50 steps \n"
+ "Page Down - Forward 50 steps \n"
+ "Left - Back 1000 steps \n"
+ "Right - Forward 1000 steps \n \n"
"NOTE: Disassembly is as memory is NOW");
break;
diff --git a/src/snap.c b/src/snap.c
new file mode 100644
index 0000000..c67c0bf
--- /dev/null
+++ b/src/snap.c
@@ -0,0 +1,200 @@
+/*
+
+ 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
+
+ -------------------------------------------------------------------------
+
+ Utilities for handling snapshots
+
+*/
+static const char ident[]="$Id$";
+
+#include "snap.h"
+
+static const char ident_h[]=ESPEC_SNAP_H;
+
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define ROMLEN 0x4000
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static Z80Word GetLSBWord(FILE *fp)
+{
+ if (fp)
+ {
+ int c1,c2;
+
+ c1=getc(fp);
+ c2=getc(fp);
+
+ if (c1==EOF || c2==EOF)
+ return 0;
+
+ return c1+(c2<<8);
+ }
+ else
+ return 0;
+}
+
+
+static void PutLSBWord(FILE *fp, Z80Word w)
+{
+ if (fp)
+ {
+ putc(w&0xff,fp);
+ putc(w>>8,fp);
+ }
+}
+
+
+static Z80Byte GetByte(FILE *fp)
+{
+ int c;
+
+ if (!fp || (c=getc(fp))==EOF)
+ return 0;
+
+ return c;
+}
+
+
+static void PutByte(FILE *fp, Z80Byte b)
+{
+ putc(b,fp);
+}
+
+
+
+/* ---------------------------------------- INTERFACES
+*/
+int TAPLoad(FILE *fp, Z80Byte id, Z80Word *addr, Z80Word *len, Z80Byte *mem)
+{
+ Z80Word blen;
+ Z80Byte type,b,csum,tape_csum;
+
+ if (!fp)
+ return FALSE;
+
+ /* Get length (wrapping file if at eof)
+ */
+ blen=GetLSBWord(fp);
+
+ if (feof(fp))
+ {
+ rewind(fp);
+ blen=GetLSBWord(fp);
+ }
+
+ type=GetByte(fp);
+ csum=id;
+
+ /* Have we found the requested block?
+ */
+ if (id==type)
+ {
+ /* Knock of block type
+ */
+ blen--;
+
+ while(blen && *len)
+ {
+ b=GetByte(fp);
+ csum^=b;
+
+ if (*addr>=ROMLEN)
+ mem[*addr]=b;
+
+ (*addr)++;
+ (*len)--;
+ blen--;
+ }
+
+ /* Get the checksum
+ */
+ if (blen)
+ {
+ tape_csum=GetByte(fp);
+ blen--;
+ }
+ else
+ tape_csum=b;
+
+ /* In case we've been request less bytes than the block size
+ */
+ while(blen--)
+ fgetc(fp);
+
+ /* Check the checksum
+ */
+ return csum==tape_csum;
+ }
+ else
+ {
+ /* If it's the wrong type, skip it
+ */
+ while(blen--)
+ fgetc(fp);
+
+ return FALSE;
+ }
+}
+
+
+int TAPSave(FILE *fp, Z80Byte id, Z80Word *addr, Z80Word *len, Z80Byte *mem)
+{
+ Z80Byte csum;
+
+ if (!fp)
+ return FALSE;
+
+ /* Write out the length and ID byte
+ */
+ PutLSBWord(fp,(*len)+2);
+ PutByte(fp,id);
+
+ /* Write out data and calc checksum
+ */
+ csum=id;
+
+ while(*len)
+ {
+ PutByte(fp,mem[*addr]);
+ csum^=mem[*addr];
+ (*addr)++;
+ (*len)--;
+ }
+
+ PutByte(fp,csum);
+
+ return TRUE;
+}
+
+
+/* END OF FILE */
diff --git a/src/snap.h b/src/snap.h
new file mode 100644
index 0000000..04d771a
--- /dev/null
+++ b/src/snap.h
@@ -0,0 +1,73 @@
+/*
+
+ espec - Sinclair Spectrum emulator
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Utilities for handling snapshots
+
+*/
+
+#ifndef ESPEC_SNAP_H
+#define ESPEC_SNAP_H "$Id$"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "z80.h"
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Loads a block from a TAP file. Returns FALSE for failure.
+ Won't write below location 0x4000 in mem.
+*/
+int TAPLoad(FILE *fp, Z80Byte id, Z80Word *addr,
+ Z80Word *len, Z80Byte *mem);
+
+
+/* Saves a block to a TAP file. Returns FALSE for failure
+ (which it never does as long as fp is not NULL).
+*/
+int TAPSave(FILE *fp, Z80Byte id, Z80Word *addr,
+ Z80Word *len, Z80Byte *mem);
+
+
+/* Copies a string. The result must be freed.
+*/
+char *StrCopy(const char *source);
+
+
+/* Returns the filename portion of path. Note returned pointer is pointing
+ inside of path.
+*/
+const char *Basename(const char *path);
+
+
+/* Returns the directory portion of path. Note returned pointer is internal
+ static storage. If there are no directory seperators in path, "." is
+ returned.
+*/
+const char *Dirname(const char *path);
+
+
+#endif
+
+
+/* END OF FILE */
diff --git a/src/spec.c b/src/spec.c
index 6ace002..bd6d5ff 100644
--- a/src/spec.c
+++ b/src/spec.c
@@ -29,6 +29,7 @@ static const char ident[]="$Id$";
#include <stdio.h>
#include <string.h>
#include "spec.h"
+#include "snap.h"
#include "gfx.h"
#include "gui.h"
#include "config.h"
@@ -44,6 +45,9 @@ static const char ident_h[]=ESPEC_SPECH;
#define FALSE 0
#endif
+#define HIBYTE(w) ((w)>>8)
+#define LOBYTE(w) ((w)&0xff)
+
/* ---------------------------------------- STATICS
*/
@@ -51,6 +55,9 @@ static const int ROMLEN=0x4000;
static const int ROM_SAVE=0x4c6;
static const int ROM_LOAD=0x562;
+static FILE *tape_in;
+static FILE *tape_out;
+
#define LOAD_PATCH 0xf0
#define SAVE_PATCH 0xf1
@@ -317,18 +324,6 @@ static void RomPatch(void)
-static void LoadTape(Z80State *state)
-{
- state->AF|=Z80_F_Carry;
-}
-
-
-static void SaveTape(Z80State *state)
-{
- state->AF|=Z80_F_Carry;
-}
-
-
static int EDCallback(Z80 *z80, Z80Val data)
{
Z80State state;
@@ -338,13 +333,39 @@ static int EDCallback(Z80 *z80, Z80Val data)
switch((Z80Byte)data)
{
case SAVE_PATCH:
- puts("Called tape save");
- SaveTape(&state);
+ if (!tape_out)
+ {
+ state.AF|=Z80_F_Carry;
+ }
+ else
+ {
+ if (TAPSave(tape_out,HIBYTE(state.AF),&state.IX,&state.DE,mem))
+ {
+ state.AF&=~Z80_F_Carry;
+ }
+ else
+ {
+ state.AF|=Z80_F_Carry;
+ }
+ }
break;
case LOAD_PATCH:
- puts("Called tape load");
- LoadTape(&state);
+ if (!tape_in)
+ {
+ state.AF|=Z80_F_Carry;
+ }
+ else
+ {
+ if (TAPLoad(tape_in,HIBYTE(state.AF),&state.IX,&state.DE,mem))
+ {
+ state.AF&=~Z80_F_Carry;
+ }
+ else
+ {
+ state.AF|=Z80_F_Carry;
+ }
+ }
break;
default:
@@ -533,7 +554,6 @@ Z80Byte SPECReadPort(Z80 *z80, Z80Word port)
default: /* ULA */
if (!(lo&1))
{
- border=(border+1)%16; /* TODO: Remove debug code */
/* Key matrix
*/
b=0xff;
@@ -580,6 +600,8 @@ Z80Byte SPECReadForDisassem(Z80 *z80, Z80Word addr)
}
+/* TODO: Implement this as a binary search
+*/
const char *SPECGetLabel(Z80 *z80, Z80Word addr)
{
static const struct
@@ -788,4 +810,48 @@ const char *SPECInfo(Z80 *z80)
}
+void SPECMount(SPECMountType type, const char *path)
+{
+ switch(type)
+ {
+ case SPEC_TAPE_IN:
+ if (tape_in)
+ fclose(tape_in);
+
+ tape_in=fopen(path,"rb");
+ break;
+
+ case SPEC_TAPE_OUT:
+ if (tape_out)
+ fclose(tape_out);
+
+ tape_out=fopen(path,"wb");
+ break;
+ }
+}
+
+
+void SPECUnmount(SPECMountType type)
+{
+ switch(type)
+ {
+ case SPEC_TAPE_IN:
+ if (tape_in)
+ {
+ fclose(tape_in);
+ tape_in=NULL;
+ }
+ break;
+
+ case SPEC_TAPE_OUT:
+ if (tape_out)
+ {
+ fclose(tape_out);
+ tape_out=NULL;
+ }
+ break;
+ }
+}
+
+
/* END OF FILE */
diff --git a/src/spec.h b/src/spec.h
index 558ba6a..bb62b91 100644
--- a/src/spec.h
+++ b/src/spec.h
@@ -31,6 +31,10 @@
#include "z80.h"
#include "SDL.h"
+/* Types for Mount and Unmount
+*/
+typedef enum {SPEC_TAPE_IN,SPEC_TAPE_OUT} SPECMountType;
+
/* Initialise the SPEC
*/
@@ -54,6 +58,11 @@ const char *SPECGetLabel(Z80 *z80, Z80Word addr);
const char *SPECInfo(Z80 *z80);
+/* Interfaces for snapshot and device control
+*/
+void SPECMount(SPECMountType type, const char *path);
+void SPECUnmount(SPECMountType type);
+
#endif
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..c3396eb
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,100 @@
+/*
+
+ espec - Sinclair Spectrum emulator
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Usual library wrappers and utils
+
+*/
+static const char ident[]="$Id$";
+
+#include <stdio.h>
+#include <string.h>
+
+#include "util.h"
+#include "exit.h"
+
+static const char ident_h[]=ESPEC_UTIL_H;
+
+
+/* ---------------------------------------- MACROS
+*/
+#define DIRSEP '/'
+
+/* ---------------------------------------- INTERFACES
+*/
+void *Malloc(size_t size)
+{
+ void *p=malloc(size);
+
+ if (!p)
+ Exit("malloc failed for %lu bytes\n",(unsigned long)size);
+
+ return p;
+}
+
+
+char *StrCopy(const char *source)
+{
+ return strcpy(Malloc(strlen(source)+1),source);
+}
+
+
+const char *Basename(const char *path)
+{
+ const char *p=path+strlen(path);
+
+ while(p>path && *p!=DIRSEP)
+ p--;
+
+ if (p>path)
+ p++;
+
+ return p;
+}
+
+
+const char *Dirname(const char *path)
+{
+ static char dir[FILENAME_MAX];
+ char *p;
+
+ strcpy(dir,path);
+
+ p=dir+strlen(dir);
+
+ while(p>dir && *p!=DIRSEP)
+ p--;
+
+ if (p>path)
+ {
+ p++;
+ *p=0;
+ }
+ else
+ {
+ strcpy(dir,".");
+ }
+
+ return dir;
+}
+
+
+/* END OF FILE */
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..f391170
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,61 @@
+/*
+
+ espec - Sinclair Spectrum emulator
+
+ Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ Usual library wrappers and utils
+
+*/
+
+#ifndef ESPEC_UTIL_H
+#define ESPEC_UTIL_H "$Id$"
+
+#include <stdlib.h>
+
+/* ---------------------------------------- INTERFACES
+*/
+
+/* Returns result from malloc(size), calling Exit() if it fails.
+*/
+void *Malloc(size_t size);
+
+
+/* Copies a string. The result must be freed.
+*/
+char *StrCopy(const char *source);
+
+
+/* Returns the filename portion of path. Note returned pointer is pointing
+ inside of path.
+*/
+const char *Basename(const char *path);
+
+
+/* Returns the directory portion of path. Note returned pointer is internal
+ static storage. If there are no directory seperators in path, "." is
+ returned.
+*/
+const char *Dirname(const char *path);
+
+
+#endif
+
+
+/* END OF FILE */