diff options
author | Ian C <ianc@noddybox.co.uk> | 2021-07-05 19:29:54 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2021-07-05 19:29:54 +0000 |
commit | 0bc192bffbf28ba5733ae955916e5ebc72f3641f (patch) | |
tree | cb68ae6e3785b2f712e3c639f687580fe75f5806 | |
parent | 25a57883291bc89210edbd3670e5548a0b838913 (diff) |
Initial working version. Still todo : Tapes, Sound
-rw-r--r-- | gfx/keyb.png | bin | 4736 -> 5892 bytes | |||
-rw-r--r-- | gfx/splashimg.png | bin | 177511 -> 86297 bytes | |||
-rw-r--r-- | include/config.h | 1 | ||||
-rw-r--r-- | include/keyboard.h | 2 | ||||
-rw-r--r-- | include/snap.h | 50 | ||||
-rw-r--r-- | include/spec.h | 8 | ||||
-rw-r--r-- | source/config.c | 5 | ||||
-rw-r--r-- | source/gui.c | 4 | ||||
-rw-r--r-- | source/main.c | 18 | ||||
-rw-r--r-- | source/snap.c | 150 | ||||
-rw-r--r-- | source/spec.c | 631 |
11 files changed, 443 insertions, 426 deletions
diff --git a/gfx/keyb.png b/gfx/keyb.png Binary files differindex c2043d1..27c84e0 100644 --- a/gfx/keyb.png +++ b/gfx/keyb.png diff --git a/gfx/splashimg.png b/gfx/splashimg.png Binary files differindex eeaa651..b8d1fa0 100644 --- a/gfx/splashimg.png +++ b/gfx/splashimg.png 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); } |