diff options
Diffstat (limited to 'arm9/source/spec.c')
-rw-r--r-- | arm9/source/spec.c | 507 |
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 */ |