summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2021-07-05 19:29:54 +0000
committerIan C <ianc@noddybox.co.uk>2021-07-05 19:29:54 +0000
commit0bc192bffbf28ba5733ae955916e5ebc72f3641f (patch)
treecb68ae6e3785b2f712e3c639f687580fe75f5806
parent25a57883291bc89210edbd3670e5548a0b838913 (diff)
Initial working version. Still todo : Tapes, Sound
-rw-r--r--gfx/keyb.pngbin4736 -> 5892 bytes
-rw-r--r--gfx/splashimg.pngbin177511 -> 86297 bytes
-rw-r--r--include/config.h1
-rw-r--r--include/keyboard.h2
-rw-r--r--include/snap.h50
-rw-r--r--include/spec.h8
-rw-r--r--source/config.c5
-rw-r--r--source/gui.c4
-rw-r--r--source/main.c18
-rw-r--r--source/snap.c150
-rw-r--r--source/spec.c631
11 files changed, 443 insertions, 426 deletions
diff --git a/gfx/keyb.png b/gfx/keyb.png
index c2043d1..27c84e0 100644
--- a/gfx/keyb.png
+++ b/gfx/keyb.png
Binary files differ
diff --git a/gfx/splashimg.png b/gfx/splashimg.png
index eeaa651..b8d1fa0 100644
--- a/gfx/splashimg.png
+++ b/gfx/splashimg.png
Binary files differ
diff --git a/include/config.h b/include/config.h
index a6734f7..b57c3ef 100644
--- a/include/config.h
+++ b/include/config.h
@@ -28,7 +28,6 @@
typedef enum
{
DSSPEC_STICKY_SHIFT,
- DSSPEC_ALLOW_TAPE_SAVE,
DSSPEC_LOAD_DEFAULT_SNAPSHOT,
DSSPEC_NUM_CONFIG_ITEMS
} DSSPEC_ConfigItem;
diff --git a/include/keyboard.h b/include/keyboard.h
index 00fdcb6..94805a0 100644
--- a/include/keyboard.h
+++ b/include/keyboard.h
@@ -73,7 +73,7 @@ typedef enum
SK_B,
SK_N,
SK_M,
- SK_PERIOD,
+ SK_SYMBOL,
SK_SPACE,
SK_ABOUT,
diff --git a/include/snap.h b/include/snap.h
new file mode 100644
index 0000000..62b6063
--- /dev/null
+++ b/include/snap.h
@@ -0,0 +1,50 @@
+/*
+ 3dsspec - Nintendo 3DS Sinclair Spectrum 48K emulator.
+
+ Copyright (C) 2021 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: snap.h 3 2006-09-13 23:49:18Z ianc $
+
+*/
+
+#ifndef DSSPEC_SNAP_H
+#define DSSPEC_SNAP_H
+
+#include "z80.h"
+
+/* ---------------------------------------- INTERFACES
+*/
+
+typedef Z80Byte (*SNAP_Peek)(Z80Word address);
+typedef void (*SNAP_Poke)(Z80Word address, Z80Byte val);
+
+
+/* Sets the active TAP file
+*/
+void TAPSetTape(Z80Byte *tap, int len);
+
+/* Loads a block from a TAP file. Returns FALSE for failure.
+*/
+int TAPLoad(Z80Byte id, Z80Word *addr,
+ Z80Word *len, SNAP_Poke poke);
+
+#endif
+
+
+/* END OF FILE */
diff --git a/include/spec.h b/include/spec.h
index b6b73eb..8b7154b 100644
--- a/include/spec.h
+++ b/include/spec.h
@@ -37,9 +37,9 @@
*/
void SPECInit(Z80 *z80);
-/* Render the display
+/* Start the frame
*/
-void SPECRenderDisplay(Framebuffer *fb, Z80 *z80);
+void SPECStartFrame(Framebuffer *fb);
/* Handle keypresses
*/
@@ -70,6 +70,10 @@ void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val);
#define SPECReadDisassem SPECReadMem
+/* Interface for snap
+*/
+void SPECWriteSnap(Z80Word addr, Z80Byte val);
+
/* Interfaces to allows the SPEC to save/load itself as a snapshot to/from
a stream.
*/
diff --git a/source/config.c b/source/config.c
index 3abc1ab..8198290 100644
--- a/source/config.c
+++ b/source/config.c
@@ -40,7 +40,6 @@ const char *conf_filename = "SPEC48.CFG";
const char *conf_entry[DSSPEC_NUM_CONFIG_ITEMS]=
{
"sticky_shift",
- "allow_tape_save",
"load_default_snapshot"
};
@@ -50,7 +49,6 @@ const char *conf_entry[DSSPEC_NUM_CONFIG_ITEMS]=
int DSSPEC_Config[DSSPEC_NUM_CONFIG_ITEMS]=
{
TRUE,
- FALSE,
FALSE
};
@@ -128,9 +126,6 @@ const char *ConfigDesc(DSSPEC_ConfigItem item)
case DSSPEC_LOAD_DEFAULT_SNAPSHOT:
return "LOAD DEFAULT SNAPSHOT";
- case DSSPEC_ALLOW_TAPE_SAVE:
- return "ALLOW TAPE SAVING";
-
default:
return "UNKNOWN";
}
diff --git a/source/gui.c b/source/gui.c
index 1d14fa3..604f910 100644
--- a/source/gui.c
+++ b/source/gui.c
@@ -850,7 +850,7 @@ int GUI_InputName(const char *prompt, const char *ext, char name[], int maxlen)
FB_Print(&upper, "PRESS ENTER TO ACCEPT", 0, 32,
COL_BLACK, COL_TRANSPARENT);
- FB_Print(&upper, "PRESS PERIOD TO BACKSPACE", 0, 40,
+ FB_Print(&upper, "PRESS SYMBOL SHIFT TO BACKSPACE", 0, 40,
COL_BLACK, COL_TRANSPARENT);
FB_Print(&upper, "PRESS SPACE/BREAK TO CANCEL", 0, 48,
COL_BLACK, COL_TRANSPARENT);
@@ -869,7 +869,7 @@ int GUI_InputName(const char *prompt, const char *ext, char name[], int maxlen)
switch(ev.key)
{
- case SK_PERIOD:
+ case SK_SYMBOL:
if (l)
{
name[--l] = 0;
diff --git a/source/main.c b/source/main.c
index 83dd070..f096f9a 100644
--- a/source/main.c
+++ b/source/main.c
@@ -60,7 +60,7 @@
*/
static const char *main_menu[]=
{
- "Reset SPEC",
+ "Reset Spectrum",
"Select Tape",
"Configure",
"Map Joypad to Keys",
@@ -122,7 +122,6 @@ static void Splash(void)
Framebuffer upper;
Framebuffer lower;
- SPECEnableFileSystem(TRUE);
SNAP_Enable(TRUE);
while(!(hidKeysDown() & KEY_A))
@@ -135,9 +134,9 @@ static void Splash(void)
FB_Blit(&upper, IMG_SPLASH, 0, scr_y);
FB_Print(&upper, "10 REM VERSION \001" DSSPEC_VERSION "\001\n"
- "20 PRINT \"\001THE SPEC IS ACE\001\"\n"
+ "20 PRINT \"\001THE SPECTRUM IS ACE\001\"\n"
"30 GOTO 20",
- 0, 230, COL_WHITE, COL_TRANSPARENT);
+ 0, 230, COL_BLACK, COL_TRANSPARENT);
FB_printf(&lower, scr_x, 8, COL_WHITE, COL_TRANSPARENT,
"%-42.42s",scroller);
@@ -191,9 +190,9 @@ static void MapJoypad(void)
FB_Clear(&upper, COL_WHITE);
FB_Print(&upper, "Press the joypad button you want\n"
- "to define and then the SPEC key\n"
- "you want to use.\n\n"
- "Press CONFIG to finish.",
+ "to define and then the Spectrum key\n"
+ "you want to use for that button.\n\n"
+ "Press MENU to finish.",
0, upper.height - 40, COL_BLACK,COL_TRANSPARENT);
if (pad != NUM_SOFT_KEYS)
@@ -263,6 +262,7 @@ int main(int argc, char *argv[])
SK_DisplayKeyboard();
SK_SetSticky(SK_SHIFT,DSSPEC_Config[DSSPEC_STICKY_SHIFT]);
+ SK_SetSticky(SK_SYMBOL,DSSPEC_Config[DSSPEC_STICKY_SHIFT]);
if (DSSPEC_Config[DSSPEC_LOAD_DEFAULT_SNAPSHOT])
{
@@ -279,9 +279,9 @@ int main(int argc, char *argv[])
SK_DisplayKeyboard();
- Z80Exec(z80);
+ SPECStartFrame(&upper);
- SPECRenderDisplay(&upper, z80);
+ Z80Exec(z80);
FB_EndFrame();
diff --git a/source/snap.c b/source/snap.c
new file mode 100644
index 0000000..1ddb6b9
--- /dev/null
+++ b/source/snap.c
@@ -0,0 +1,150 @@
+/*
+
+ 3dsspec - Nintendo 3DS Sinclair Spectrum 48K emulator.
+
+ Copyright (C) 2021 Ian Cowburn
+
+ 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: snap.c 4 2006-09-15 00:30:18Z ianc $
+
+*/
+#include "snap.h"
+
+/* ---------------------------------------- MACROS
+*/
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define ROMLEN 0x4000
+
+
+/* ---------------------------------------- PRIVATE DATA
+*/
+static Z80Byte *tap_file;
+static int tap_len;
+static int tap_ptr;
+
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+static Z80Byte GetByte(void)
+{
+ Z80Byte ret=0;
+
+ if (tap_len)
+ {
+ ret=tap_file[tap_ptr];
+ tap_ptr=(tap_ptr+1)%tap_len;
+ }
+
+ return ret;
+}
+
+
+static Z80Word GetLSBWord(void)
+{
+ int c1,c2;
+
+ c1=GetByte();
+ c2=GetByte();
+
+ return c1+(c2<<8);
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+void TAPSetTape(Z80Byte *tape, int len)
+{
+ tap_file = tape;
+ tap_len = len;
+ tap_ptr = 0;
+}
+
+
+int TAPLoad(Z80Byte id, Z80Word *addr, Z80Word *len, SNAP_Poke poke)
+{
+ Z80Word blen;
+ Z80Byte type,b,csum,tape_csum;
+
+ if (!tap_file)
+ {
+ return FALSE;
+ }
+
+ b=0;
+
+ blen=GetLSBWord();
+ type=GetByte();
+ csum=id;
+
+ /* Have we found the requested block?
+ */
+ if (id==type)
+ {
+ /* Knock of block type
+ */
+ blen--;
+
+ while(blen && *len)
+ {
+ b=GetByte();
+ csum^=b;
+
+ poke(*addr,b);
+
+ (*addr)++;
+ (*len)--;
+ blen--;
+ }
+
+ /* Get the checksum
+ */
+ if (blen)
+ {
+ tape_csum=GetByte();
+ blen--;
+ }
+ else
+ tape_csum=b;
+
+ /* In case we've been request less bytes than the block size
+ */
+ while(blen--)
+ GetByte();
+
+ /* Check the checksum
+ */
+ return csum==tape_csum;
+ }
+ else
+ {
+ /* If it's the wrong type, skip it
+ */
+ while(blen--)
+ GetByte();
+
+ return FALSE;
+ }
+}
+
+
+/* END OF FILE */
diff --git a/source/spec.c b/source/spec.c
index e5932da..5fa5060 100644
--- a/source/spec.c
+++ b/source/spec.c
@@ -30,6 +30,7 @@
#include "spec.h"
#include "gui.h"
#include "framebuffer.h"
+#include "snap.h"
#include "stream.h"
@@ -45,63 +46,92 @@
#define FALSE 0
#endif
+#define HIBYTE(w) ((w)>>8)
+#define LOBYTE(w) ((w)&0xff)
+
/* ---------------------------------------- STATICS
*/
#define ROMLEN 0x4000
-#define ROM_SAVE 0x2fc
-#define ROM_LOAD 0x347
+#define ROM_SAVE 0x4c6
+#define ROM_LOAD 0x562
#define ED_SAVE 0xf0
#define ED_LOAD 0xf1
-#define SLOW_TSTATES 16000
-#define FAST_TSTATES 64000
-
-#define E_LINE 16404
-#define LASTK1 16421
-#define LASTK2 16422
-#define MARGIN 16424
-#define FRAMES 16436
-#define CDFLAG 16443
-
-#define NMI_PERIOD 208
+#define SCAN_CYCLES 224
-/* The SPEC screen and memory
+/* The 3DS screen
*/
-static int fast_mode=FALSE;
-static int nmigen=FALSE;
-static int hsync=FALSE;
-static int drawing_screen=FALSE;
-static int ula_line_counter;
+#define GFX_W 400
+#define GFX_H 240
-static u16 black;
-static u16 white;
+/* The Spectrum screen and memory
+*/
+#define SCR_W 256
+#define SCR_H 192
+#define TXT_W 32
+#define TXT_H 24
+#define SCRDATA 0x4000
+#define ATTR 0x5800
-#define SCR_W 256
-#define SCR_H 192
-#define TXT_W 32
-#define TXT_H 24
+#define OFF_X ((GFX_W-SCR_W)/2)
+#define OFF_Y ((GFX_H-SCR_H)/2)
-static Z80Byte mem[0x10000];
+#define ATTR_AT(x,y) mem[ATTR+(x)+((y)/8)*32]
-static u16 screen[SCR_W*SCR_H];
-static int ula_ptr;
+Z80Byte mem[0x10000];
-static Z80Word RAMBOT=0;
-static Z80Word RAMTOP=0;
+static int border;
+static int scanline;
-#define DFILE 0x400c
+#define TOPL 64 /* Scanlines before 'first' line */
+#define SCRL SCR_H /* Scanlines making up screen data */
+#define BOTL 56 /* Scanlines after 'last' line */
-#define WORD(a) (mem[a] | (Z80Word)mem[a+1]<<8)
+#define TOTL (TOPL+SCRL+BOTL)
-/* Tape
+/* GFX vars
*/
-static int enable_filesystem;
-static int allow_save;
-static const Z80Byte *tape_image;
-static int tape_len;
+#define FLASH 16 /* Frames per flash */
+
+static Framebuffer *fb;
+
+static int flash=0;
+static int flashctr=0;
+
+#define NVAL 205 /* Normal RGB intensity */
+#define BVAL 255 /* Bright RGB intensity */
+
+static Z80Byte *line[SCR_H]; /* Accelerators to screen data */
+
+#define NO_COLS 16
+
+static struct
+{
+ u16 col;
+ int r,g,b;
+} coltable[NO_COLS]=
+{
+ {0, 0x00,0x00,0x00}, /* BLACK */
+ {0, 0x00,0x00,NVAL}, /* BLUE */
+ {0, NVAL,0x00,0x00}, /* RED */
+ {0, NVAL,0x00,NVAL}, /* MAGENTA */
+ {0, 0x00,NVAL,0x00}, /* GREEN */
+ {0, 0x00,NVAL,NVAL}, /* CYAN */
+ {0, NVAL,NVAL,0x00}, /* YELLOW */
+ {0, NVAL,NVAL,NVAL}, /* WHITE */
+
+ {0, 0x00,0x00,0x00}, /* BLACK */
+ {0, 0x00,0x00,BVAL}, /* BLUE */
+ {0, BVAL,0x00,0x00}, /* RED */
+ {0, BVAL,0x00,BVAL}, /* MAGENTA */
+ {0, 0x00,BVAL,0x00}, /* GREEN */
+ {0, 0x00,BVAL,BVAL}, /* CYAN */
+ {0, BVAL,BVAL,0x00}, /* YELLOW */
+ {0, BVAL,BVAL,BVAL}, /* WHITE */
+
+};
-static char last_dir[FILENAME_MAX] = "/";
/* The keyboard
*/
@@ -126,29 +156,20 @@ static struct
/* ---------------------------------------- PRIVATE FUNCTIONS
*/
-#define PEEKW(addr) (mem[addr] | (Z80Word)mem[addr+1]<<8)
-
-#define POKEW(addr,val) do \
- { \
- Z80Word wa=addr; \
- Z80Word wv=val; \
- mem[wa]=wv; \
- mem[wa+1]=wv>>8; \
- } while(0)
-
static void RomPatch(void)
{
static const Z80Byte save[]=
{
0xed, ED_SAVE, /* (SAVE) */
- 0xc3, 0x07, 0x02, /* JP $0207 */
+ 0xc9, /* RET */
0xff /* End of patch */
};
static const Z80Byte load[]=
{
+ 0x08, /* EX AF,AF' */
0xed, ED_LOAD, /* (LOAD) */
- 0xc3, 0x07, 0x02, /* JP $0207 */
+ 0xc9, /* RET */
0xff /* End of patch */
};
@@ -165,176 +186,108 @@ static void RomPatch(void)
}
}
-/* Open a tape file the passed address
-*/
-static FILE *OpenTapeFile(Z80Word addr, int *cancelled, const char *mode)
+
+static void DrawScanline(int y, int sline)
{
- static const char zx_chars[] = "\"#$:?()><=+-*/;,."
- "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- FILE *fp;
- char full_fn[FILENAME_MAX] = DEFAULT_SNAPDIR;
- char fn[FILENAME_MAX];
- int f;
- int done;
+ int aline;
+ int f,r;
+ int ink,paper,t;
+ Z80Byte *scr;
+ Z80Byte b;
+ Z80Byte att;
- fp = NULL;
- f = 0;
- done = FALSE;
- *cancelled = FALSE;
+ aline=sline-TOPL;
- while(f<(FILENAME_MAX-3) && !done)
+ y = fb->height - y - 1;
+
+ for(f = 0; f < fb->width; f++)
{
- int ch;
+ FB_ADDR(fb, f, y) = coltable[border].col;
+ }
- ch = mem[addr++];
+ if (aline>=0 && aline<SCRL)
+ {
+ scr=line[aline];
- if (ch&0x80)
+ for(f=0;f<TXT_W;f++)
{
- done = TRUE;
- ch &= 0x7f;
- }
+ att=ATTR_AT(f,aline);
- if (ch>=11 && ch<=63)
- {
- fn[f++] = zx_chars[ch-11];
- }
- }
+ ink=(att&0x07);
+ paper=(att&0x38)>>3;
- if (fn[0] == '*')
- {
- if (GUI_FileSelect(last_dir,fn,".P"))
- {
- fp = fopen(fn, mode);
- }
- else
- {
- *cancelled = TRUE;
- }
+ if (att&0x40)
+ {
+ ink+=8;
+ paper+=8;
+ }
- SK_DisplayKeyboard();
- }
- else
- {
- fn[f++] = '.';
- fn[f++] = 'P';
- fn[f] = 0;
+ if ((att&0x80)&&(flash))
+ {
+ t=ink;
+ ink=paper;
+ paper=t;
+ }
- strcat(full_fn,fn);
+ for(r=0,b=*scr++;r<8;r++)
+ {
+ if (b & 0x80)
+ {
+ FB_ADDR(fb, f*8+r+OFF_X, y) = coltable[ink].col;
+ }
+ else
+ {
+ FB_ADDR(fb, f*8+r+OFF_X, y) = coltable[paper].col;
+ }
- if (!(fp = fopen(full_fn, mode)))
- {
- fp = fopen(fn, mode);
+ b = b << 1;
+ }
}
}
-
- return fp;
-}
-
-
-static void LoadInternalTape(Z80 *z80)
-{
- memcpy(mem+0x4009,tape_image,tape_len);
}
-static void LoadExternalTape(FILE *tape, Z80 *z80)
+static int CheckTimers(Z80 *z80, Z80Val val)
{
- int c;
- Z80Byte *a;
-
- a=mem+0x4009;
+ int ret = TRUE;
- while((c=getc(tape))!=EOF)
+ if (val > SCAN_CYCLES)
{
- *a++=c;
- }
-}
-
+ int y;
-static void SaveExternalTape(FILE *tape, Z80 *z80)
-{
- int f;
- int end;
+ Z80ResetCycles(z80, val-SCAN_CYCLES);
- f = 0x4009;
- end = WORD(E_LINE);
+ /* Increment scan line and check for frame flyback
+ */
+ scanline++;
- while(f <= end)
- {
- fputc(mem[f++], tape);
- }
-}
+ if (scanline==TOTL)
+ {
+ scanline=0;
+ flashctr++;
-static int CheckTimers(Z80 *z80, Z80Val val)
-{
- static Z80Word last_PC;
- static Z80Byte last_R;
- int ret = TRUE;
+ if (flashctr==FLASH)
+ {
+ flash^=1;
+ flashctr=0;
+ }
- /* See if we're started or stopping executing the display file
- */
- if (z80->PC > 0x7fff)
- {
- if (last_PC < 0x8000)
- {
- drawing_screen = TRUE;
- ula_ptr = 0;
- }
- }
+ Z80Interrupt(z80,0xff);
- if (z80->PC < 0x8000)
- {
- if (last_PC > 0x7fff && ula_ptr == SCR_W * SCR_H)
- {
- drawing_screen = FALSE;
- ula_ptr = 0;
- Z80ResetCycles(z80, val - SLOW_TSTATES);
ret = FALSE;
- }
- }
+ }
- last_PC = z80->PC;
+ /* Draw scanline
+ */
+ y = scanline - TOPL + OFF_Y;
- /* Check HSYNC generation
- */
- if (hsync && !nmigen)
- {
- if (last_R & 0x40 && !(z80->R & 0x40))
+ if (y >= 0 && y < fb->height)
{
- Z80Interrupt(z80, 0xff);
- ula_line_counter = (ula_line_counter + 1) % 8;
+ DrawScanline(y, scanline);
}
- }
-
- last_R = z80->R;
- /* Check NMI generator
- */
- if (nmigen && val > NMI_PERIOD)
- {
- Z80NMI(z80);
- Z80ResetCycles(z80, val - NMI_PERIOD);
- }
-
- /* We should only be able to execute FAST_TSTATES if we're not drawing the
- screen.
- */
- if (val >= FAST_TSTATES)
- {
- Z80ResetCycles(z80,val-FAST_TSTATES);
-
- if (mem[CDFLAG] & 0x80)
- {
- fast_mode = FALSE;
- }
- else
- {
- fast_mode = TRUE;
- }
-
- ret = FALSE;
+ /* TODO: Process sound emulation */
}
return ret;
@@ -346,58 +299,23 @@ static int EDCallback(Z80 *z80, Z80Val data)
switch((Z80Byte)data)
{
case ED_SAVE:
- if (allow_save && z80->DE.w<0x8000)
- {
- FILE *fp;
- int cancel;
-
- if ((fp=OpenTapeFile(z80->HL.w, &cancel, "wb")))
- {
- SaveExternalTape(fp,z80);
- fclose(fp);
- }
- }
+ z80->AF.b[Z80_LO_WORD] &= ~eZ80_Carry;
break;
case ED_LOAD:
- /* Try and load the external file if a name given. Otherwise, we
- try the internal one. Some of this is slightly dodgy -- it was
- never intended for the emulator to be doing any GUI related
- nonsense (like the alerts) but simply emulating.
- */
- if (enable_filesystem && z80->DE.w<0x8000)
+ if (TAPLoad(z80->AF.b[Z80_HI_WORD],
+ &z80->IX.w,
+ &z80->DE.w,
+ SPECWriteSnap))
{
- FILE *fp;
- int cancel;
-
- if ((fp=OpenTapeFile(z80->DE.w, &cancel, "rb")))
- {
- LoadExternalTape(fp,z80);
- fclose(fp);
- }
- else
- {
- if (!cancel)
- {
- GUI_Alert(FALSE,"Couldn't open tape");
- SK_DisplayKeyboard();
- }
- }
+ z80->AF.b[Z80_LO_WORD] |= eZ80_Carry;
+ z80->BC.w=0xb001;
}
else
{
- if (tape_image)
- {
- LoadInternalTape(z80);
- }
- else
- {
- GUI_Alert(FALSE,"No tape image selected");
- SK_DisplayKeyboard();
- }
+ z80->AF.b[Z80_LO_WORD] &= ~eZ80_Carry;
+ z80->BC.w = 0xff01;
}
-
- mem[CDFLAG]=0xc0;
break;
default:
@@ -412,10 +330,14 @@ static int EDCallback(Z80 *z80, Z80Val data)
*/
void SPECInit(Z80 *z80)
{
- Z80Word f;
+ int f;
- black = FB_GetColour(COL_BLACK);
- white = FB_GetColour(COL_WHITE);
+ for(f = 0; f < NO_COLS; f++)
+ {
+ coltable[f].col = RGB8_to_565(coltable[f].r,
+ coltable[f].g,
+ coltable[f].b);
+ }
/* Load the ROM
*/
@@ -427,58 +349,13 @@ void SPECInit(Z80 *z80)
Z80LodgeCallback(z80,eZ80_EDHook,EDCallback);
Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers);
- /* Mirror the ROM
- */
- memcpy(mem+ROMLEN,mem,ROMLEN);
-
- /* Memory size (16K)
- */
- RAMBOT=0x4000;
- RAMTOP=RAMBOT+0x4000;
-
- for(f = RAMBOT; f <= RAMTOP; f++)
- {
- mem[f] = 0;
- }
-
- for(f = 0; f < 8; f++)
- {
- matrix[f] = 0x1f;
- }
+ SPECReset(z80);
}
-void SPECRenderDisplay(Framebuffer *fb, Z80 *z80)
+void SPECStartFrame(Framebuffer *framebuffer)
{
- if (fast_mode)
- {
- u16 x;
- u16 y;
-
- for(x = 0; x < fb->width; x++)
- {
- for(y = 0; y < fb->height; y++)
- {
- FB_ADDR(fb, x, y) = ((x+y) % 2) ? black : white;
- }
- }
- }
- else
- {
- int x;
- int y;
-
- FB_Clear(fb, COL_WHITE);
-
- for(y = 0; y < SCR_H; y++)
- {
- for(x = 0; x < SCR_W; x++)
- {
- FB_ADDR(fb, 72 + x, fb->height - 24 - y) =
- screen[x + y * SCR_W];
- }
- }
- }
+ fb = framebuffer;
}
@@ -497,75 +374,29 @@ void SPECHandleKey(SoftKey key, int is_pressed)
}
else
{
- /* TODO: Joysticks? Were there any common ones for the 81? */
+ /* TODO: Joysticks? */
}
}
Z80Byte SPECReadMem(Z80 *z80, Z80Word addr)
{
- if (addr & 0x8000)
- {
- Z80Byte b;
-
- b = mem[addr & 0x7fff];
-
- /* If bit 6 of the byte is set it is sent to the CPU, otherwise it is
- used to generate the video signal and zero sent to the CPU
- */
- if (b & 0x40)
- {
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- screen[ula_ptr++] = white;
- }
- else
- {
- Z80Word base;
- int inv;
- int f;
-
- inv=b & 0x80;
- b &= 0x3f;
-
- base = ((Z80Word)z80->I<<8)|(b<<3)|ula_line_counter;
-
- b = mem[base];
-
- for(f = 0; f < 8; f++)
- {
- if (b & 0x80)
- {
- screen[ula_ptr++] = rand(); // inv ? white : black;
- }
- else
- {
- screen[ula_ptr++] = rand(); // inv ? black : white;
- }
-
- b = b << 1;
- }
+ return mem[addr];
+}
- b = 0;
- }
- return b;
- }
- else
+void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val)
+{
+ if (addr>=ROMLEN)
{
- return mem[addr];
+ mem[addr]=val;
}
}
-void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val)
+void SPECWriteSnap(Z80Word addr, Z80Byte val)
{
- if (addr>=RAMBOT && addr<=RAMTOP)
+ if (addr>=ROMLEN)
{
mem[addr]=val;
}
@@ -574,55 +405,39 @@ void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val)
Z80Byte SPECReadPort(Z80 *z80, Z80Word port)
{
- Z80Byte b=0;
+ Z80Byte lo=port&0xff;
+ Z80Byte hi=port>>8;
+ Z80Byte b=0xff;
+ int f;
- switch(port&0xff)
+ switch(lo)
{
- 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;
- }
-
- /* Some code expects some of the top bits set... Of course, whether
- or not this may be worse as other code doesn't expect the bits,
- we shall find out!
- */
- b |= 0x60;
+ case 0x1f: /* Kempston joystick */
+ break;
- /* Reset ULA line counter
- */
- ula_line_counter = 0;
+ case 0x7f: /* Fuller joystick */
+ break;
+ case 0xfb: /* ZX Printer */
break;
- default:
- b = 0xff; /* Idle bus */
+ default: /* ULA */
+ if (!(lo&1))
+ {
+ /* Key matrix
+ */
+ b=0xff;
+
+ for(f=0;f<8;f++)
+ if (!(hi&(1<<f)))
+ b&=matrix[f];
+
+ b|=0xa0;
+
+ /* TODO: Emulation of contention? */
+ }
+ else
+ b=0xff;
break;
}
@@ -632,20 +447,19 @@ Z80Byte SPECReadPort(Z80 *z80, Z80Word port)
void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val)
{
- switch(port&0xff)
+ Z80Byte lo=port&0xff;
+
+ switch(lo)
{
- case 0xfd: /* NMI generator OFF */
- nmigen = FALSE;
+ case 0xfe: /* ULA */
+ border = val & 0x07;
break;
- case 0xfe: /* NMI generator ON */
- nmigen = TRUE;
- Z80ResetCycles(z80, 0);
+ case 0xfb: /* ZX Printer */
break;
- case 0xff: /* HSYNC generator ON */
- hsync = TRUE;
- break;
+ default:
+ break;
}
}
@@ -653,6 +467,8 @@ void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val)
void SPECReset(Z80 *z80)
{
int f;
+ int c;
+ int r;
for(f=0;f<8;f++)
matrix[f]=0x1f;
@@ -660,27 +476,32 @@ void SPECReset(Z80 *z80)
Z80Reset(z80);
Z80ResetCycles(z80,0);
- nmigen = FALSE;
- hsync = FALSE;
-}
-
+ border = 0;
+ scanline = 0;
-void SPECEnableFileSystem(int enable)
-{
- enable_filesystem=enable;
-}
+ /* Set up screen
+ */
+ c=0;
+ r=0;
+ for(f=0;f<SCRL;f++)
+ {
+ line[f]=mem+SCRDATA+(c*8*TXT_W)+(r*TXT_W);
+ c++;
-void SPECSetTape(const Z80Byte *image, int len)
-{
- tape_image=image;
- tape_len=len;
+ if ((c%8)==0)
+ {
+ if (++r==8)
+ r=0;
+ else
+ c-=8;
+ }
+ }
}
void SPECReconfigure(void)
{
- allow_save = enable_filesystem && DSSPEC_Config[DSSPEC_ALLOW_TAPE_SAVE];
}
@@ -698,8 +519,7 @@ void SPECSaveSnapshot(FILE *fp)
PUT_Byte(fp, matrix[f]);
}
- PUT_ULong(fp, RAMBOT);
- PUT_ULong(fp, RAMTOP);
+ PUT_Byte(fp, border);
}
@@ -717,8 +537,7 @@ void SPECLoadSnapshot(FILE *fp)
matrix[f] = GET_Byte(fp);
}
- RAMBOT = GET_ULong(fp);
- RAMTOP = GET_ULong(fp);
+ border = GET_Byte(fp);
}