/* dsspec - Nintendo DS Sinclair Spectrum 48K emulator. Copyright (C) 2006 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$ */ #include #include #include #include #include "spec.h" #include "snap.h" #include "spec48_bin.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define HIBYTE(w) ((w)>>8) #define LOBYTE(w) ((w)&0xff) /* ---------------------------------------- STATICS */ static uint16 *vram; static const int ROMLEN=0x4000; static const int ROM_SAVE=0x4c6; static const int ROM_LOAD=0x562; #define LOAD_PATCH 0xf0 #define SAVE_PATCH 0xf1 /* The SPEC screen */ #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) Z80_MEMORY[ATTR+(x)+((y)/8)*32] Z80Byte Z80_MEMORY[0x10000]; /* Number of cycles per frame */ static Z80Val FRAME_CYCLES=69888; /* GFX vars */ #define FLASH 16 /* Frames per flash */ static int flash=0; static int flashctr=0; #define NVAL 25 /* Normal RGB intensity */ #define BVAL 31 /* Bright RGB intensity */ static Z80Byte *line[SCR_H]; /* Accelerators to screen data */ static struct { uint16 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]; static struct { int row; int bit; } key_matrix[]= { {3,0x01}, {3,0x02}, {3,0x04}, {3,0x08}, {3,0x10}, /* 1 - 5 */ {4,0x10}, {4,0x08}, {4,0x04}, {4,0x02}, {4,0x01}, /* 6 - 0 */ {2,0x01}, {2,0x02}, {2,0x04}, {2,0x08}, {2,0x10}, /* Q - T */ {5,0x10}, {5,0x08}, {5,0x04}, {5,0x02}, {5,0x01}, /* Y - P */ {1,0x01}, {1,0x02}, {1,0x04}, {1,0x08}, {1,0x10}, /* A - G */ {6,0x10}, {6,0x08}, {6,0x04}, {6,0x02}, {6,0x01}, /* H - NL */ {0,0x01}, {0,0x02}, {0,0x04}, {0,0x08}, {0,0x10}, /* CAPS - V */ {7,0x10}, {7,0x08}, {7,0x04}, {7,0x02}, {7,0x01} /* B - SPACE */ }; static int debug_matrix = FALSE; /* ---------------------------------------- PRIVATE FUNCTIONS */ static void FillBox(int x, int y, int w, int h, int colour) { int f; uint16 *base; colour|=0x8000; base=vram+x+y*256; while(h--) { for(f=0;f>3; if (att&0x40) { ink+=8; paper+=8; } if ((att&0x80)&&(flash)) { t=ink; ink=paper; paper=t; } b=*scr++; for(r=0;r<8;r++) { if (b&(1<<(7-r))) { *vr++=coltable[ink].col; } else { *vr++=coltable[paper].col; } } } } if (debug_matrix) { int m; int b; for(m=0;m<8;m++) { for(b=0;b<8;b++) { uint16 col; if (matrix[m]&(1<=ROMLEN) Z80_MEMORY[addr]=val; } void SnapPoke(Z80Word addr, Z80Byte val) { if (addr>=ROMLEN) Z80_MEMORY[addr]=val; } static int EDCallback(Z80 *z80, Z80Val data) { Z80State state; switch((Z80Byte)data) { case SAVE_PATCH: state.AF&=~eZ80_Carry; Z80SetState(z80,&state); break; case LOAD_PATCH: Z80GetState(z80,&state); if (TAPLoad(HIBYTE(state.AF), &state.IX, &state.DE, SnapPoke)) { state.AF|=eZ80_Carry; state.BC=0xb001; } else { state.AF&=~eZ80_Carry; state.BC=0xff01; } Z80SetState(z80,&state); break; default: break; } return TRUE; } static int CheckTimers(Z80 *z80, Z80Val val) { if (val>FRAME_CYCLES) { Z80ResetCycles(z80,val-FRAME_CYCLES); flashctr++; if (flashctr==FLASH) { flash^=1; flashctr=0; } Z80Interrupt(z80,0xff); DrawScreen(); /* TODO: Process sound emulation */ return FALSE; } else { return TRUE; } } /* ---------------------------------------- EXPORTED INTERFACES */ void SPECInit(uint16 *v, Z80 *z80) { vram=v; memcpy(Z80_MEMORY,spec48_bin,ROMLEN); /* Patch the ROM */ RomPatch(); Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); SPECReset(z80); } void SPECHandleKey(SoftKey key, int is_pressed) { if (key>8; Z80Byte b=0xff; int f; switch(lo) { case 0x1f: /* Kempston joystick */ break; case 0x7f: /* Fuller joystick */ break; case 0xfb: /* ZX Printer */ break; default: /* ULA */ if (!(lo&1)) { /* Key matrix */ b=0xff; for(f=0;f<8;f++) if (!(hi&(1<