diff options
Diffstat (limited to 'arm9/source/zx81.c')
-rw-r--r-- | arm9/source/zx81.c | 792 |
1 files changed, 0 insertions, 792 deletions
diff --git a/arm9/source/zx81.c b/arm9/source/zx81.c deleted file mode 100644 index 41ff686..0000000 --- a/arm9/source/zx81.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - ds81 - Nintendo DS ZX81 emulator - - Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> - - 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 - - ------------------------------------------------------------------------- - - Provides the emulation for the zX81 - -*/ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <nds.h> - -#include "ds81_global.h" - -#include "zx81.h" -#include "gui.h" - -#include "zx81_bin.h" - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#define MAX_FNAME_LEN 30 - - -/* ---------------------------------------- STATICS -*/ -#define ROMLEN 0x2000 -#define ROM_SAVE 0x2fc -#define ROM_LOAD 0x347 - -#define ED_SAVE 0xf0 -#define ED_LOAD 0xf1 -#define ED_WAITKEY 0xf2 -#define ED_ENDWAITKEY 0xf3 -#define ED_PAUSE 0xf4 - -#define SLOW_TSTATES 16000 -#define FAST_TSTATES 64000 - -#define LASTK1 16421 -#define LASTK2 16422 -#define MARGIN 16424 -#define FRAMES 16436 -#define CDFLAG 16443 - -static Z80Val FRAME_TSTATES=FAST_TSTATES; - -/* The ZX81 screen and memory -*/ -static int waitkey=FALSE; -static int started=FALSE; - -#define SCR_W 256 -#define SCR_H 192 -#define TXT_W 32 -#define TXT_H 24 - -static Z80Byte mem[0x10000]; - -static Z80Word RAMBOT=0; -static Z80Word RAMTOP=0; -static Z80Word RAMLEN=0; - -#define DFILE 0x400c - -#define WORD(a) (mem[a] | (Z80Word)mem[a+1]<<8) - -/* Tape -*/ -static int enable_filesystem; -static const Z80Byte *tape_image; -static int tape_len; - -/* GFX vars -*/ -static uint16 *screen; - -/* 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 */ - }; - - -/* ---------------------------------------- PRIVATE FUNCTIONS -*/ -#define PEEKW(addr) (mem[addr] | (Z80Word)mem[addr+1]<<8) - -#define POKEW(addr,val) do \ - { \ - Z80Word wa=addr; \ - Z80Word wv=val; \ - mem[wa]=wv; \ - mem[wa+1]=wv>>8; \ - } while(0) - -static void RomPatch(void) -{ - static const Z80Byte save[]= - { - 0xed, ED_SAVE, /* (SAVE) */ - 0xc3, 0x07, 0x02, /* JP $0207 */ - 0xff /* End of patch */ - }; - - static const Z80Byte load[]= - { - 0xed, ED_LOAD, /* (LOAD) */ - 0xc3, 0x07, 0x02, /* JP $0207 */ - 0xff /* End of patch */ - }; - - static const Z80Byte fast_hack[]= - { - 0xed, ED_WAITKEY, /* (START KEY WAIT) */ - 0xcb,0x46, /* L: bit 0,(hl) */ - 0x28,0xfc, /* jr z,L */ - 0xed, ED_ENDWAITKEY, /* (END KEY WAIT) */ - 0x00, /* nop */ - 0xff /* End of patch */ - }; - - static const Z80Byte kbd_hack[]= - { - 0x2a,0x25,0x40, /* ld hl,(LASTK) */ - 0xc9, /* ret */ - 0xff /* End of patch */ - }; - - static const Z80Byte pause_hack[]= - { - 0xed, ED_PAUSE, /* (PAUSE) */ - 0x00, /* nop */ - 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]; - } - - for(f=0;fast_hack[f]!=0xff;f++) - { - mem[0x4ca+f]=fast_hack[f]; - } - - for(f=0;kbd_hack[f]!=0xff;f++) - { - mem[0x2bb+f]=kbd_hack[f]; - } - - for(f=0;pause_hack[f]!=0xff;f++) - { - mem[0xf3a+f]=pause_hack[f]; - } - - /* Trust me, we have a ZX81... Honestly. - */ - mem[0x21c]=0x00; - mem[0x21d]=0x00; - - /* Remove HALTs as we don't do interrupts - */ - mem[0x0079]=0; - mem[0x02ec]=0; -} - -static Z80Byte FromASCII(char c) -{ - switch(c) - { - case '\'': - case '"': - return 11; - - case '(': - return 16; - - case ')': - return 17; - - case '-': - return 22; - - case '*': - return 23; - - case ',': - return 26; - - case '.': - return 27; - } - - if (c>='0' && c<='9') - return (c-'0')+28; - - if (c>='a' && c<='z') - return (c-'a')+38; - - if (c>='A' && c<='Z') - return (c-'A')+38; - - return 0; -} - - -/* Open a tape file the passed address -*/ -static FILE *OpenTapeFile(Z80Word addr) -{ - FILE *fp; - char fn[MAX_FNAME_LEN]; - int f; - int done; - - f=0; - done=FALSE; - - while(f<(MAX_FNAME_LEN-3) && !done) - { - int ch; - - ch=mem[addr++]; - - if (ch&0x80) - { - done=TRUE; - ch&=0x7f; - } - - switch(ch) - { - case 22: - fn[f++]='-'; - break; - - case 27: - fn[f++]='.'; - - default: - if (ch>=28 && ch<=37) - { - fn[f++]='0'+(ch-28); - } - else if (ch>=38 && ch<=63) - { - fn[f++]='A'+(ch-38); - } - break; - } - } - - fn[f++]='.'; - fn[f++]='P'; - fn[f]=0; - - if (!(fp=fopen(fn,"rb"))) - { - char full_fn[MAX_FNAME_LEN+11]="\\ZX81SNAP\\"; - - strcat(full_fn,fn); - fp=fopen(full_fn,"rb"); - } - - return fp; -} - - -static void LoadInternalTape(Z80 *z80) -{ - memcpy(mem+0x4009,tape_image,tape_len); -} - - -static void LoadExternalTape(FILE *tape, Z80 *z80) -{ - int c; - Z80Byte *a; - - a=mem+0x4009; - - while((c=getc(tape))!=EOF) - { - *a++=c; - } -} - - -static void DrawScreen(Z80 *z80) -{ - Z80Byte *scr=mem+WORD(DFILE); - int x,y; - - x=0; - y=0; - - while(y<TXT_H) - { - scr++; - x=0; - - while((*scr!=118)&&(x<TXT_W)) - { - Z80Byte ch = *scr++; - - if (ch&0x80) - { - screen[x+y*32]=(ch&0x3f)|0x40; - } - else - { - screen[x+y*32]=(ch&0x3f); - } - - x++; - } - - y++; - } -} - - -static void DrawSnow(Z80 *z80) -{ - uint16 *s; - int f; - - s = screen; - - for(f=0;f<TXT_W*TXT_H;f++) - { - *s++=8; - } -} - - -/* Perform ZX81 housekeeping functions like updating FRAMES and updating LASTK -*/ -static void ZX81HouseKeeping(Z80 *z80) -{ - static unsigned prev_lk1,prev_lk2; - unsigned row; - unsigned lastk1; - unsigned lastk2; - - /* British ZX81 - */ - mem[MARGIN]=55; - - /* Update FRAMES - */ - if (FRAME_TSTATES==SLOW_TSTATES) - { - Z80Word frame=PEEKW(FRAMES)&0x7fff; - - if (frame) - { - frame--; - } - - POKEW(FRAMES,frame|0x8000); - } - - if (!started) - { - prev_lk1=0; - prev_lk2=0; - return; - } - - /* Update LASTK - */ - lastk1=0; - lastk2=0; - - for(row=0;row<8;row++) - { - unsigned b; - - b=(~matrix[row]&0x1f)<<1; - - if (row==0) - { - unsigned shift; - - shift=b&2; - b&=~2; - b|=(shift>>1); - } - - if (b) - { - if (b>1) - { - lastk1|=(1<<row); - } - - lastk2|=b; - } - } - - if (lastk1 && (lastk1!=prev_lk1 || lastk2!=prev_lk2)) - { - mem[CDFLAG]|=1; - } - else - { - mem[CDFLAG]&=~1; - } - - mem[LASTK1]=lastk1^0xff; - mem[LASTK2]=lastk2^0xff; - - prev_lk1=lastk1; - prev_lk2=lastk2; -} - - -static int CheckTimers(Z80 *z80, Z80Val val) -{ - if (val>=FRAME_TSTATES) - { - Z80ResetCycles(z80,val-FRAME_TSTATES); - - if (started && ((mem[CDFLAG] & 0x80) || waitkey)) - { - DrawScreen(z80); - FRAME_TSTATES=SLOW_TSTATES; - } - else - { - DrawSnow(z80); - FRAME_TSTATES=FAST_TSTATES; - } - - /* Update FRAMES (if in SLOW) and scan the keyboard. This only happens - once we've got to a decent point in the boot cycle (detected with - a valid stack pointer). - */ - if (z80->SP<0x8000) - { - ZX81HouseKeeping(z80); - } - - swiWaitForVBlank(); - - return FALSE; - } - else - { - return TRUE; - } -} - - -static int EDCallback(Z80 *z80, Z80Val data) -{ - Z80Word pause; - - switch((Z80Byte)data) - { - case ED_SAVE: - break; - - case ED_LOAD: - /* Try and load the external file if a name given. Otherwise, we - try the internal one. Some of this is slightly dodgy -- it was - never intended for the emulator to be doing any GUI related - nonsense (like the alerts) but simply emulating. - */ - if (enable_filesystem && z80->DE.w<0x8000) - { - FILE *fp; - - if ((fp=OpenTapeFile(z80->DE.w))) - { - LoadExternalTape(fp,z80); - fclose(fp); - } - else - { - GUI_Alert(FALSE,"Couldn't open tape"); - SK_DisplayKeyboard(BG_GFX_SUB); - } - } - else - { - if (tape_image) - { - LoadInternalTape(z80); - } - else - { - GUI_Alert(FALSE,"No tape image selected"); - SK_DisplayKeyboard(BG_GFX_SUB); - } - } - - mem[CDFLAG]=0xc0; - break; - - case ED_WAITKEY: - waitkey=TRUE; - started=TRUE; - break; - - case ED_ENDWAITKEY: - waitkey=FALSE; - break; - - case ED_PAUSE: - waitkey=TRUE; - - pause=z80->BC.w; - - while(pause-- && !(mem[CDFLAG]&1)) - { - SoftKeyEvent ev; - - while (SK_GetEvent(&ev)) - { - ZX81HandleKey(ev.key,ev.pressed); - } - - CheckTimers(z80,FRAME_TSTATES); - } - - waitkey=FALSE; - break; - - default: - break; - } - - return TRUE; -} - - -/* ---------------------------------------- EXPORTED INTERFACES -*/ -void ZX81Init(uint16 *vram, Z80 *z80) -{ - Z80Word f; - - screen = vram; - - /* Load the ROM - */ - memcpy(mem,zx81_bin,ROMLEN); - - /* Patch the ROM - */ - RomPatch(); - Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); - Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); - - /* Mirror the ROM - */ - memcpy(mem+ROMLEN,mem,ROMLEN); - - - /* Memory size (16K) - */ - RAMBOT=0x4000; - RAMLEN=0x4000; - RAMTOP=RAMBOT+RAMLEN; - - for(f=RAMBOT;f<=RAMTOP;f++) - mem[f]=0; - - for(f=0;f<8;f++) - matrix[f]=0x1f; -} - - -void ZX81HandleKey(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? */ - } -} - - -Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) -{ - /* Hopefully by simply returning RET for ULA reads we save a lot of - ROM patching shenanigans. - */ - if (addr>0x7fff) - { - return 0xc9; - } - else - { - return mem[addr]; - } -} - - -void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) -{ - if (addr>=RAMBOT && addr<=RAMTOP) - { - mem[addr]=val; - } -} - - -Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) -{ - Z80Byte b=0; - - switch(port&0xff) - { - case 0xfe: /* ULA */ - /* Key matrix - */ - switch(port&0xff00) - { - case 0xfe00: - b=matrix[0]; - break; - case 0xfd00: - b=matrix[1]; - break; - case 0xfb00: - b=matrix[2]; - break; - case 0xf700: - b=matrix[3]; - break; - case 0xef00: - b=matrix[4]; - break; - case 0xdf00: - b=matrix[5]; - break; - case 0xbf00: - b=matrix[6]; - break; - case 0x7f00: - b=matrix[7]; - break; - } - break; - - default: - break; - } - - return b; -} - - -void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) -{ - switch(port&0xff) - { - case 0xfd: - break; - - case 0xfe: - break; - } -} - - -void ZX81Reset(Z80 *z80) -{ - int f; - - for(f=0;f<8;f++) - matrix[f]=0x1f; - - Z80Reset(z80); - Z80ResetCycles(z80,0); - - started=FALSE; -} - - -void ZX81EnableFileSystem(int enable) -{ - enable_filesystem=enable; -} - - -void ZX81SetTape(const Z80Byte *image, int len) -{ - tape_image=image; - tape_len=len; -} - - -void ZX81DisplayString(const char *p) -{ - uint16 *s; - uint16 inv=0; - int f; - - s = screen; - - for(f=0;f<TXT_W*TXT_H;f++) - { - *s++=0; - } - - s = screen; - f = 0; - - while(*p) - { - switch(*p) - { - case '\n': - s+=32; - f=0; - break; - - case '%': - inv^=0x40; - break; - - default: - s[f++]=FromASCII(*p)|inv; - break; - } - - p++; - } -} - - -/* END OF FILE */ |