summaryrefslogtreecommitdiff
path: root/arm9/source/spec.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2007-04-10 23:59:35 +0000
committerIan C <ianc@noddybox.co.uk>2007-04-10 23:59:35 +0000
commit6701f6a9d4f979cc1eadb673e767b5c46cd2a9c8 (patch)
tree5996a9d0a8bb393afc4ef3da9609df7a22af32a1 /arm9/source/spec.c
parentcd4886b4b099367c561fa5af6d7346bd43d7e2a7 (diff)
Initial import
Diffstat (limited to 'arm9/source/spec.c')
-rw-r--r--arm9/source/spec.c507
1 files changed, 507 insertions, 0 deletions
diff --git a/arm9/source/spec.c b/arm9/source/spec.c
new file mode 100644
index 0000000..70b1931
--- /dev/null
+++ b/arm9/source/spec.c
@@ -0,0 +1,507 @@
+/*
+ ds48 - Nintendo DS ZX Spectrum emulator.
+
+ Copyright (C) 2007 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 "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<w;f++)
+ {
+ *(base+f)=colour;
+ }
+
+ base+=256;
+ }
+}
+
+
+
+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;
+ }
+ }
+ }
+ }
+
+ 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<<b))
+ {
+ col=RGB15(0,31,0);
+ }
+ else
+ {
+ col=RGB15(31,0,0);
+ }
+
+ FillBox((7-b)*5,150+m*5,4,4,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++)
+ Z80_MEMORY[ROM_SAVE+f]=save[f];
+
+ for(f=0;load[f]!=0xff;f++)
+ Z80_MEMORY[ROM_LOAD+f]=load[f];
+}
+
+
+Z80Byte SPECPeek(Z80 *cpu, Z80Word addr)
+{
+ return Z80_MEMORY[addr];
+}
+
+
+void SPECPoke(Z80 *cpu, Z80Word addr, Z80Byte val)
+{
+ if (addr>=ROMLEN)
+ Z80_MEMORY[addr]=val;
+}
+
+
+static int EDCallback(Z80 *z80, Z80Val data)
+{
+ switch((Z80Byte)data)
+ {
+ case SAVE_PATCH:
+ z80->AF.w&=~eZ80_Carry;
+ break;
+
+ case LOAD_PATCH:
+ /*
+ if (TAPLoad(HIBYTE(state.AF),
+ z80->IX,
+ z80->DE,
+ SnapPoke))
+ {
+ state.AF|=eZ80_Carry;
+ state.BC=0xb001;
+ }
+ else
+ {
+ state.AF&=~eZ80_Carry;
+ state.BC=0xff01;
+ }
+ */
+
+ 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<SK_CONFIG)
+ {
+ if (is_pressed)
+ {
+ matrix[key_matrix[key].row]&=~key_matrix[key].bit;
+ }
+ else
+ {
+ matrix[key_matrix[key].row]|=key_matrix[key].bit;
+ }
+ }
+ else
+ {
+ /* TODO: Joysticks! */
+
+ if (is_pressed && key==SK_PAD_SELECT)
+ {
+ debug_matrix = !debug_matrix;
+ }
+ }
+}
+
+
+void SPECEnableFileSystem(int enable)
+{
+}
+
+
+void SPECSetTape(const Z80Byte *image, int len)
+{
+}
+
+
+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]=Z80_MEMORY+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);
+}
+
+
+void SPECReconfigure(void)
+{
+}
+
+
+/* END OF FILE */