diff options
author | Ian C <ianc@noddybox.co.uk> | 2006-09-13 23:49:18 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2006-09-13 23:49:18 +0000 |
commit | e007fe3daeff4bcd64bd41894d5606fe43948672 (patch) | |
tree | 489ae3bf888f235321423b41269bfae463b18c18 /source/spec.c | |
parent | f7c8435b666daac5a30c88e462727a6c3dbf584d (diff) |
Initail version with Spectrum booting
Diffstat (limited to 'source/spec.c')
-rw-r--r-- | source/spec.c | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/source/spec.c b/source/spec.c new file mode 100644 index 0000000..7137834 --- /dev/null +++ b/source/spec.c @@ -0,0 +1,456 @@ +/* + + 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <nds.h> + +#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) mem[ATTR+(x)+((y)/8)*32] + +static Z80Byte mem[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]; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void DrawScreen(void) +{ + int f,r; + int ink,paper,t; + int y; + Z80Byte *scr; + Z80Byte b; + Z80Byte att; + uint16 *vr; + + vr=vram; + + swiWaitForVBlank(); + + for(y=0;y<SCR_H;y++) + { + scr=line[y]; + + for(f=0;f<TXT_W;f++) + { + att=ATTR_AT(f,y); + + ink=(att&0x07); + paper=(att&0x38)>>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; + } + } + } + } +} + +static void RomPatch(void) +{ + static const Z80Byte save[]= + { + 0xed, SAVE_PATCH, /* ED illegal op */ + 0xc9, /* RET */ + 0xff /* End of patch */ + }; + + static const Z80Byte load[]= + { + 0x08, /* EX AF,AF' */ + 0xed, LOAD_PATCH, /* ED illegal op */ + 0xc9, /* RET */ + 0xff /* End of patch */ + }; + + int f; + + for(f=0;save[f]!=0xff;f++) + mem[ROM_SAVE+f]=save[f]; + + for(f=0;load[f]!=0xff;f++) + mem[ROM_LOAD+f]=load[f]; +} + + +Z80Byte SPECPeek(Z80 *cpu, Z80Word addr) +{ + return mem[addr]; +} + + +Z80Byte SnapPeek(Z80Word addr) +{ + return mem[addr]; +} + + +void SPECPoke(Z80 *cpu, Z80Word addr, Z80Byte val) +{ + if (addr>=ROMLEN) + mem[addr]=val; +} + + +void SnapPoke(Z80Word addr, Z80Byte val) +{ + if (addr>=ROMLEN) + mem[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(mem,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<=SK_SPACE) + { + int row; + int bit; + + row=key/5; + + if (row&1) + { + bit=5-(key%5); + } + else + { + bit=(key%5); + } + + if (is_pressed) + { + matrix[row]&=~bit; + } + else + { + matrix[row]|=bit; + } + } + else + { + /* TODO: Joysticks! */ + } +} + + +Z80Byte SPECReadPort(Z80 *z80, Z80Word port) +{ + Z80Byte lo=port&0xff; + Z80Byte hi=port>>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<<f))) + b&=matrix[f]; + + b|=0xa0; + + /* TODO: Emulation of contention? */ + } + else + b=0xff; + break; + } + + return b; +} + + +void SPECWritePort(Z80 *z80, Z80Word port, Z80Byte val) +{ + Z80Byte lo=port&0xff; + + switch(lo) + { + case 0xfe: /* ULA */ + break; + + case 0xfb: /* ZX Printer */ + break; + + default: + break; + } +} + + +void SPECReset(Z80 *z80) +{ + int f; + int c; + int r; + + /* Set up the keyboard + */ + for(f=0;f<8;f++) + { + matrix[f]=0x1f; + } + + /* Set up the colours + */ + for(f=0;f<16;f++) + { + coltable[f].col=0x8000|RGB15(coltable[f].r,coltable[f].g,coltable[f].b); + } + + flash=0; + flashctr=0; + + /* Set up screen + */ + c=0; + r=0; + for(f=0;f<SCR_H;f++) + { + line[f]=mem+SCRDATA+(c*8*TXT_W)+(r*TXT_W); + + c++; + + if ((c%8)==0) + { + if (++r==8) + r=0; + else + c-=8; + } + } + + Z80ResetCycles(z80,0); + Z80Reset(z80); +} + + +/* END OF FILE */ |