/* Emulation of the Z80 CPU with hooks into the other parts of xz80. * Copyright (C) 1994 Ian Collier. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "zx.h" #define parity(a) (partable[a]) unsigned char partable[256]={ 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4 }; #ifdef DEBUG static unsigned short breakpoint=0; static unsigned int breaks=0; //static void inline log(fp,name,val) static void log(fp,name,val) FILE *fp; char *name; unsigned short val; { int i; fprintf(fp,"%s=%04X ",name,val); for(i=0;i<8;i++,val++)fprintf(fp," %02X",fetch(val)); putc('\n',fp); } #endif void mainloop(word spc, word ssp){ register unsigned char a, f, b, c, d, e, h, l; unsigned char r, a1, f1, b1, c1, d1, e1, h1, l1, i, iff1, iff2, im; register unsigned short pc; unsigned short ix, iy, sp; register unsigned long tstates; register unsigned int radjust; register unsigned char ixoriy, new_ixoriy; unsigned char intsample; register unsigned char op; #ifdef DEBUG char flags[9]; int bit; FILE *fp=0; register unsigned short af2=0,bc2=0,de2=0,hl2=0,ix2=0,iy2=0,sp2=0; register unsigned char i2=0; //unsigned char *memory=memptr[0]; struct _next {unsigned char bytes[8];} *next; unsigned short BC, DE, HL, AF; fputs("Press F11 to log\n",stderr); #endif a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1=h1=l1=i=r=iff1=iff2=im=0; ixoriy=new_ixoriy=0; ix=iy=0; pc=spc; sp=ssp; tstates=radjust=0; while(1){ ixoriy=new_ixoriy; new_ixoriy=0; #ifdef DEBUG next=(struct _next *)&fetch(pc); BC=bc;DE=de;HL=hl;AF=(a<<8)|f; if(fp && !ixoriy){ log(fp,"pc",pc); if(sp!=sp2)log(fp,"sp",sp2=sp); if(iy!=iy2)log(fp,"iy",iy2=iy); if(ix!=ix2)log(fp,"ix",ix2=ix); if(hl!=hl2)log(fp,"hl",hl2=hl); if(de!=de2)log(fp,"de",de2=de); if(bc!=bc2)log(fp,"bc",bc2=bc); if(((a<<8)|f)!=af2){ af2=(a<<8)|f; strcpy(flags,"SZ H VNC"); for(bit=0;bit<8;bit++)if(!(f&(1<<(7-bit))))flags[bit]=' '; fprintf(fp,"af=%04X %s\n",af2,flags); } if(i!=i2)fprintf(fp,"ir=%02X%02X\n",i2=i,r); putc('\n',fp); } if(pc==breakpoint && pc) breaks++; /* some code at which to set a breakpoint */ a=AF>>8; f=AF; h=HL>>8; l=HL; d=DE>>8; e=DE; b=BC>>8; c=BC; #endif /* { static int tr = 0; static int id = 0; // static byte b = 0; // if (pc == 0x1177) tr = 1; if (pc == 0x1185) tr = 0; if (tr >= 1) ++id; if (tr >= 1) printf("%d: PC=%04x %02x AF=%02x:%02x BC=%04x DE=%04x HL=%04x IX=%04x IY=%04x\r\n", id, pc, fetch(pc), a,f, bc, de, hl, ix, iy); } */ intsample=1; op=fetch(pc); pc++; radjust++; switch(op){ #include "z80ops.h" } /*** * ZXCC doesn't do interrupts at all, so all this is commented out if(tstates>=int_cycles && intsample){ tstates-=int_cycles; frames++; // Carry out X-related tasks (including waiting for timer // signal if necessary) switch(interrupt()){ case Z80_quit: #ifdef DEBUG if(fp)fclose(fp); #endif return; case Z80_NMI: if(fetch(pc)==0x76)pc++; iff2=iff1; iff1=0; // The Z80 performs a machine fetch cycle for 5 Tstates // but ignores the result. It takes a further 10 Tstates // to jump to the NMI routine at 0x66. tstates+=15; push2(pc); pc=0x66; break; case Z80_reset: a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1= h1=l1=i=r=iff1=iff2=im=0; ix=iy=sp=pc=0; radjust=0; break; #ifdef DEBUG case Z80_log: if(fp){ fclose(fp); fp=0; fputs("Logging turned off\n",stderr); } else { fp=fopen(config.log,"a"); if(fp)fprintf(stderr,"Logging to file %s\n",config.log); else perror(config.log); } break; #endif case Z80_load: stopwatch(); if(snapload()){ a=snapa; f=snapf; b=snapb; c=snapc; d=snapd; e=snape; h=snaph; l=snapl; a1=snapa1; f1=snapf1; b1=snapb1; c1=snapc1; d1=snapd1; e1=snape1; h1=snaph1; l1=snapl1; iff1=snapiff1; iff2=snapiff2; i=snapi; r=snapr; radjust=r; im=snapim; ix=snapix; iy=snapiy; sp=snapsp; pc=snappc; } startwatch(1); break; case Z80_save: r=(r&0x80)|(radjust&0x7f); snapa=a; snapf=f; snapb=b; snapc=c; snapd=d; snape=e; snaph=h; snapl=l; snapa1=a1; snapf1=f1; snapb1=b1; snapc1=c1; snapd1=d1; snape1=e1; snaph1=h1; snapl1=l1; snapiff1=iff1; snapiff2=iff2; snapi=i; snapr=r; snapim=im; snapix=ix; snapiy=iy; snapsp=sp; snappc=pc; snapsave(); startwatch(1); break; } if(iff1){ #ifdef DEBUG if(fp)fprintf(fp,"Interrupt (im=%d)\n\n",im); #endif if(fetch(pc)==0x76)pc++; iff1=iff2=0; tstates+=5; // accompanied by an input from the data bus // switch(im){ case 0: // IM 0 // case 1: // undocumented // case 2: // IM 1 // // there is little to distinguish between these cases // tstates+=8; push2(pc); pc=0x38; break; case 3: // IM 2 // tstates+=14; { int addr=fetch2((i<<8)|0xff); push2(pc); pc=addr; } } } }*/ } }