summaryrefslogtreecommitdiff
path: root/source/spec.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2006-09-13 23:49:18 +0000
committerIan C <ianc@noddybox.co.uk>2006-09-13 23:49:18 +0000
commite007fe3daeff4bcd64bd41894d5606fe43948672 (patch)
tree489ae3bf888f235321423b41269bfae463b18c18 /source/spec.c
parentf7c8435b666daac5a30c88e462727a6c3dbf584d (diff)
Initail version with Spectrum booting
Diffstat (limited to 'source/spec.c')
-rw-r--r--source/spec.c456
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 */