/* 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 #include #include #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=0x4000; static const int ROM_SAVE=0x4c6; static const int ROM_LOAD=0x562; /* The SPEC screen */ #define GFX_W 320 #define GFX_H 300 #define SCR_W 256 #define SCR_H 192 #define TXT_W 32 #define TXT_H 24 #define SCRDATA 0x4000 #define ATTR 0x5800 #define ATTR_AT(x,y) \ mem[ATTR+(x)+((y)/8)*32] static const int OFF_X=(GFX_W-SCR_W)/2; static const int OFF_Y=(GFX_H-SCR_H)/2; static Z80Byte mem[0x10000]; /* Number of cycles per scan lines and scan line control */ static Z80Val SCAN_CYCLES=224; static int scanline=0; /* GFX vars */ #define FLASH 16 /* Frames per flash */ static int flash=0; static int flashctr=0; static int border=0; #define TOPL 64 /* Scanlines before 'first' line */ #define SCRL SCR_H /* Scanlines making up screen data */ #define BOTL 56 /* Scanlines after 'last' line */ #define TOTL (TOPL+SCRL+BOTL) #define NVAL 235 /* Normal RGB intensity */ #define BVAL 255 /* Bright RGB intensity */ static struct { Uint32 col; int r,g,b; } coltable[16]= { {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 */ }; /* The keyboard */ static Z80Byte matrix[8]; typedef struct { SDLKey key; int m1,b1,m2,b2; } MatrixMap; #define KY1(m,b) m,1<=0 && aline>3; if (att&0x40) { ink+=8; paper+=8; } if ((att&0x80)&&(flash)) { t=ink; ink=paper; paper=t; } for(r=7,b=*scr++;r>=0;r--) if (b&(1<AF|=Z80_F_Carry; } static void SaveTape(Z80State *state) { state->AF|=Z80_F_Carry; } 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; } Z80SetState(z80,&state); return TRUE; } static int CheckTimers(Z80 *z80, Z80Val val) { if (val>SCAN_CYCLES) { int y; Z80ResetCycles(z80,val-SCAN_CYCLES); /* Increment scan line and check for frame flyback */ scanline++; if (scanline==TOTL) { scanline=0; flashctr++; if (flashctr==FLASH) { flash^=1; flashctr=0; } Z80Interrupt(z80,0xff); GFXEndFrame(TRUE); GFXStartFrame(); } /* Draw scanline y=OFF_X-TOPL+scanline; */ y=scanline-TOPL+OFF_Y; if (y>=0 && ykey!=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) { /* TODO: Emulation of contention */ return mem[addr]; } void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val) { if (addr>=ROMLEN) mem[addr]=val; } Z80Byte SPECReadPort(Z80 *z80, Z80Word port) { Z80Byte lo=port&0xff; Z80Byte hi=port>>8; Z80Byte b=0xff; int f; switch(lo) { case 0x1f: /* TODO: Kempston joystick */ break; case 0x7f: /* TODO: Fuller joystick */ break; case 0xfb: /* TODO: ZX Printer */ break; case 0x01: /* ULA */ /* Key matrix */ b=0; for(f=0;f<8;f++) if (!(hi&(1<