home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 18
/
aminetcdnumber181997.iso
/
Aminet
/
misc
/
emu
/
gbuk.lha
/
src
/
GB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-22
|
20KB
|
607 lines
/** VGB: portable GameBoy emulator ***************************/
/** **/
/** GB.c **/
/** **/
/** This file contains the portable part of the GameBoy **/
/** hardware emulation. See GB.h for #defines related to **/
/** drivers and GameBoy hardware. **/
/** **/
/** Copyright (C) Marat Fayzullin 1995,1996 **/
/** Marcel de Kogel 1996 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "GB.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
// PG CHANGE ->Verbose has default of 0
//byte Verbose = 1; /* Verboseness level */
byte Verbose = 0; /* Verboseness level */
byte *RAM,*Page[8]; /* RAM and pointers to Z80 address space 8x8kB) */
int VPeriod = 6000; /* Number of Z80 cycles between VBlanks */
byte UPeriod = 1; /* Number of VBlanks per screen update */
byte LineDelay = 1; /* When 1, CMPLINE interrupts are delayed */
byte CheckCRC = 1; /* When 1, VGB checks cartridge CRC on loading */
char *SaveName = NULL; /* .sav file name */
struct /* Cheat list to be filled before StartGB() */
{ /* is called */
byte Value,Orig;
word Address;
} Cheats[MAXCHEAT];
int CheatCount = 0; /* Number of cheats in the list */
byte SIOBuf; /* Next byte to output via the serial line */
byte SIOFlag; /* Bit0 -> SIO interrupt should be generated */
/* Bit1 -> Data should be sent out */
byte IMask; /* A mask to reset an event bit in IFLAGS */
byte MBCType; /* MBC type: 1 for MBC2, 0 for MBC1 */
byte *ROMMap[256]; /* Addresses of ROM banks */
byte ROMBank; /* Number of ROM bank currently used */
byte ROMMask; /* Mask for the ROM bank number */
int ROMBanks; /* Total number of ROM banks */
byte *RAMMap[256]; /* Addresses of RAM banks */
byte RAMBank; /* Number of RAM bank currently used */
byte RAMMask; /* Mask for the RAM bank number */
int RAMBanks; /* Total number of RAM banks */
byte JoyState = 0xFF; /* Joystick state: START.SELECT.B.A.D.U.L.R */
byte BPal[4]; /* Background palette */
byte SPal0[4],SPal1[4]; /* Sprite palettes */
byte *ChrGen; /* Character generator */
byte *BgdTab,*WndTab; /* Background and window character tables */
byte SprFlag = 0; /* <>0: sprites were enabled during the frame */
// got rid of reg param thing
static void WriteROM (word A,byte V);
static void WriteRAM (word A,byte V);
static void WROMBank (word A,byte V);
static void WRAMBank (word A,byte V);
static void WriteIO(word A,byte V);
int IFreq=60;
static void WriteRAM (word A,byte V)
{
Page[A>>13][A&0x1FFF]=V;
}
static void WROMBank (word A,byte V)
{
if(MBCType&&((A&0xFF00)!=0x2100)) return;
V&=ROMMask;
if(!V) V++;
if(ROMMask&&(V!=ROMBank))
{
ROMBank=V;
Page[2]=ROMMap[V]? ROMMap[V]:RAM+0x4000;
Page[3]=Page[2]+0x2000;
if(Verbose&0x08) printf("ROM: Bank %d selected\n",V);
}
}
static void WriteROM (word A,byte V)
{
if(Verbose&0x02) printf("Wrote %Xh to ROM at %Xh\n",V,A);
}
static void WRAMBank (word A,byte V)
{
byte v;
v=V;
V&=RAMMask;
if(RAMMask&&!MBCType&&(RAMBank!=V))
{
RAMBank=V;
Page[5]=RAMMap[V]? RAMMap[V]:RAM+0xA000;
if(Verbose&0x08) printf("RAM: Bank %d selected\n",v);
}
}
// -PG- got rid if static declaration
unsigned TimerTestParam=0;
unsigned TimerRecurParam=65536/32;
static void WriteIO(word A,byte V)
{
static unsigned TPFreqs[] = { 4096,262144,65536,16384 };
register byte *P;
switch(A)
{
case 0xFF00: JOYPAD=0xCF|V;
if(!(V&0x20)) JOYPAD&=(JoyState>>4)|0xF0;
if(!(V&0x10)) JOYPAD&=JoyState|0xF0;
return;
case 0xFF01: SIOBuf=V;SIOFlag|=0x02;return;
case 0xFF02: if(V&0x80)
{
if((SIOFlag&0x02)? SIOSend(SIOBuf):SIOReceive(&SIODATA))
SIOFlag|=0x01;
SIOFlag=(SIOFlag&0xFD);
}
V|=0x7E;
break;
case 0xFF05: /*V=0;*/
break;
case 0xFF07: TimerRecurParam=(TPFreqs[V&0x03]<<16)/(154*IFreq);
V|=0xF8;break;
case 0xFF0F: V|=0xE0;break;
case 0xFFFF: V|=0xE0;break;
case 0xFF46: P=RAM+0xFE00;A=(word)V<<8;
for(V=0;V<0xA0;V++) *P++=M_RDMEM(A++);
return;
case 0xFF41: V=(V&0xF8)|(LCDSTAT&0x07);
break;
case 0xFF40: ChrGen=RAM+(V&0x10? 0x8000:0x8800);
BgdTab=RAM+(V&0x08? 0x9C00:0x9800);
WndTab=RAM+(V&0x40? 0x9C00:0x9800);
break;
case 0xFF44: V=0;break;
case 0xFF47: BPal[0]=V&0x03;
BPal[1]=(V&0x0C)>>2;
BPal[2]=(V&0x30)>>4;
BPal[3]=(V&0xC0)>>6;
break;
case 0xFF48: SPal0[0]=V&0x03;
SPal0[1]=(V&0x0C)>>2;
SPal0[2]=(V&0x30)>>4;
SPal0[3]=(V&0xC0)>>6;
break;
case 0xFF49: SPal1[0]=V&0x03;
SPal1[1]=(V&0x0C)>>2;
SPal1[2]=(V&0x30)>>4;
SPal1[3]=(V&0xC0)>>6;
break;
case 0xFF04: case 0xFF06: /* other documented ports */
case 0xFF42: case 0xFF43: case 0xFF45: case 0xFF4A: case 0xFF4B:
case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34:
case 0xFF35: case 0xFF36: case 0xFF37: case 0xFF38: case 0xFF39:
case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E:
case 0xFF3F:
break;
default: if((A>=0xFF10)&&(A<=0xFF26)) Sound(A-0xFF10,V);
/* else if (A<0xFF80) printf ("Wrote %02x to %04x\n",V,A); */
}
Page[7][A&0x1FFF]=V;
}
WriteMemFn WriteMemFnTable[256]= {
/* 0000-1FFF ROM */
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
/* 2000-3FFF ROM Bank Select */
WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,
WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,
WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,
WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,WROMBank,
/* 4000-5FFF RAM Bank Select */
WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,
WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,
WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,
WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,WRAMBank,
/* 6000-7FFF ROM */
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,WriteROM,
/* 8000-FEFF RAM */
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,WriteRAM,
/* FF00-FFFF I/O */
WriteIO
};
#ifndef FAST_MEM
void M_WRMEM (word A,byte V)
{
(*WriteMemFnTable[A>>8])(A,V);
}
byte M_RDMEM(register word A)
{
byte V;
V=(Page[A>>13][A&0x1FFF]);
return V;
}
#endif
static int InitMachineDone=0;
static word Exit_PC;
int StartGB(char *CartName)
{
static char *CartTypes[] =
{
"ROM ONLY","ROM+MBC1","ROM+MBC1+RAM",
"ROM+MBC1+RAM+BATTERY","UNKNOWN",
"ROM+MBC2","ROM+MBC2+BATTERY"
};
static struct { word Code;char *Name; } Companies[] =
{
{ 0x3301,"Nintendo" },{ 0x7901,"Accolade" },{ 0xA400,"Konami" },
{ 0x6701,"Ocean" },{ 0x5601,"LJN" },{ 0x9900,"ARC?" },
{ 0x0101,"Nintendo" },{ 0x0801,"Capcom" },{ 0x0100,"Nintendo" },
{ 0xBB01,"SunSoft" },{ 0xA401,"Konami" },{ 0xAF01,"Namcot?" },
{ 0x4901,"Irem" },{ 0x9C01,"Imagineer" },{ 0xA600,"Kawada?" },
{ 0xB101,"Nexoft" },{ 0x5101,"Acclaim" },{ 0x6001,"Titus" },
{ 0xB601,"HAL" },{ 0x3300,"Nintendo" },{ 0x0B00,"Coconuts?" },
{ 0x5401,"Gametek" },{ 0x7F01,"Kemco?" },{ 0xC001,"Taito" },
{ 0xEB01,"Atlus" },{ 0xE800,"Asmik?" },{ 0xDA00,"Tomy?" },
{ 0xB100,"ASCII?" },{ 0xEB00,"Atlus" },{ 0xC000,"Taito" },
{ 0x9C00,"Imagineer" },{ 0xC201,"Kemco?" },{ 0xD101,"Sofel?" },
{ 0x6101,"Virgin" },{ 0xBB00,"SunSoft" },{ 0xCE01,"FCI?" },
{ 0xB400,"Enix?" },{ 0xBD01,"Imagesoft" },{ 0x0A01,"Jaleco?" },
{ 0xDF00,"Altron?" },{ 0xA700,"Takara?" },{ 0xEE00,"IGS?" },
{ 0x8300,"Lozc?" },{ 0x5001,"Absolute?" },{ 0xDD00,"NCS?" },
{ 0xE500,"Epoch?" },{ 0xCB00,"VAP?" },{ 0x8C00,"Vic Tokai" },
{ 0xC200,"Kemco?" },{ 0xBF00,"Sammy?" },
{ 0x1800,"Hudson Soft" },{ 0xCA01,"Palcom/Ultra" },
{ 0xCA00,"Palcom/Ultra" },{ 0xC500,"Data East?" },
{ 0xA900,"Technos Japan?" },{ 0xD900,"Banpresto?" },
{ 0x7201,"Broderbund?" },{ 0x7A01,"Triffix Entertainment?" },
{ 0xE100,"Towachiki?" },{ 0x9300,"Tsuburava?" },
{ 0xC600,"Tonkin House?" },{ 0xCE00,"Pony Canyon" },
{ 0x7001,"Infogrames?" },{ 0x8B01,"Bullet-Proof Software?" },
{ 0x5501,"Park Place?" },{ 0xEA00,"King Records?" },
{ 0x5D01,"Tradewest?" },{ 0x6F01,"ElectroBrain?" },
{ 0xAA01,"Broderbund?" },{ 0xC301,"SquareSoft" },
{ 0x5201,"Activision?" },{ 0x5A01,"Bitmap Brothers/Mindscape" },
{ 0x5301,"American Sammy" },{ 0x1801,"Hudson Soft"},{ 0x0000,NULL }
};
int Checksum,I,J,*T;
FILE *F;
char *P,S[50];
word A;
reg R;
int rambanks[4]= { 0,1,1,4 };
/*** STARTUP CODE starts here: ***/
T=(int *)"\01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
#ifdef LSB_FIRST
if(*T!=1)
{
puts("********** This machine is high-endian. *********");
puts("Take #define LSB_FIRST out and compile VGB again.");
return(0);
}
#else
if(*T==1)
{
puts("********* This machine is low-endian. *********");
puts("Insert #define LSB_FIRST and compile VGB again.");
return(0);
}
#endif
for(I=0;I<256;I++) RAMMap[I]=ROMMap[I]=NULL;
if(Verbose) printf("Allocating 64kB for address space...");
if(!(RAM=malloc(0x10000)))
{ if(Verbose) puts("FAILED");return(0); }
memset(RAM,NORAM,0x10000);
for(I=0;I<8;I++) Page[I]=RAM+I*0x2000;
if(Verbose) printf("OK\nOpening %s...",CartName);
if(!(F=fopen(CartName,"rb")))
{ if(Verbose) puts("FAILED");return(0); }
if(Verbose) printf("reading...");
if(fread(RAM,1,0x4000,F)!=0x4000)
{ if(Verbose) puts("FAILED");return(0); }
ROMMap[0]=RAM;
ROMBanks=2<<RAM[0x0148];
RAMBanks=rambanks[RAM[0x0149]&3]; /* (1<<RAM[0x0149]*2)>>1; */
Checksum=((word)RAM[0x014E]<<8)+RAM[0x014F];
MBCType=RAM[0x0147]>3;
P=NULL;
if((RAM[0x0147]==4)||(RAM[0x0147]>6)) P="Unknown ROM type";
if(P)
{
printf("\nError loading cartridge: %s\n",P);
fclose(F);return(0);
}
if(Verbose)
{
strncpy(S,RAM+0x0134,16);S[16]='\0';
printf("OK\n Name: %s\n",S);
printf(" Type: %s\n",CartTypes[RAM[0x0147]]);
printf(" ROM Size: %dx16kB\n",ROMBanks);
printf(" RAM Size: %dx8kB\n",RAMBanks);
J=((word)RAM[0x014B]<<8)+RAM[0x014A];
for(I=0,P=NULL;!P&&Companies[I].Name;I++)
if(J==Companies[I].Code) P=Companies[I].Name;
printf(" Manufacturer ID: %Xh",J);
printf(" [%s]\n",P? P:"?");
printf(" Version Number: %Xh\n",RAM[0x014C]);
printf(" Complement Check: %Xh\n",RAM[0x014D]);
printf(" Checksum: %Xh\n",Checksum);
J=((word)RAM[0x0103]<<8)+RAM[0x0102];
printf(" Start Address: %Xh\n",J);
}
Checksum+=RAM[0x014E]+RAM[0x014F];
for(I=0;I<0x4000;I++) Checksum-=RAM[I];
if(Verbose) printf("Loading %dx16kB ROM banks:\n.",ROMBanks);
for(I=1;I<ROMBanks;I++)
if(ROMMap[I]=malloc(0x4000))
if(fread(ROMMap[I],1,0x4000,F)==0x4000)
{
for(J=0;J<0x4000;J++) Checksum-=ROMMap[I][J];
if(Verbose) putchar('.');
}
else { if(Verbose) puts("READ FAILED");break; }
else { if(Verbose) puts("MALLOC FAILED");break; }
fclose(F);if(I<ROMBanks) return(0);
if(CheckCRC&&(Checksum&0xFFFF))
{ puts("\nError loading cartridge: Checksum is wrong");return(0); }
if(Verbose) puts("OK");
if(RAMBanks&&!MBCType)
{
if(Verbose) printf("Allocating %dx8kB RAM banks...",RAMBanks);
for(I=0;I<RAMBanks;I++)
if(RAMMap[I]=malloc(0x2000))
memset(RAMMap[I],0,0x2000);
else
{ if(Verbose) puts("FAILED");return(0); }
if(Verbose) puts("OK");
}
if((RAM[0x0147]==3)||(RAM[0x0147]==6))
/* if(SaveName=malloc(strlen(CartName)+10)) */
if (SaveName) /* SaveName is initialized in the startup code */
{
/*
strcpy(SaveName,CartName);
if(P=strrchr(SaveName,'.')) strcpy(P,".sav");
else strcat(SaveName,".sav");
*/
if(Verbose) printf("Opening %s...",SaveName);
if(F=fopen(SaveName,"rb"))
{
if(Verbose) printf("reading...");
J=RAM[0x0147]==3? 0x2000:0x0200;
J=(fread(RAMMap[0]? RAMMap[0]:Page[5],1,J,F)==J);
if(Verbose) puts(J? "OK":"FAILED");
fclose(F);
}
else if(Verbose) puts("FAILED");
}
if(CheatCount>0)
{
if(Verbose) puts("Patching cheats into the ROM code:");
for(J=0;J<CheatCount;J++)
{
A=Cheats[J].Address;
if(Verbose)
printf(" at %Xh: %Xh -> %Xh\n",A,Cheats[J].Orig,Cheats[J].Value);
if(A<0x4000)
{ if(ROMMap[0][A]==Cheats[J].Orig) ROMMap[0][A]=Cheats[J].Value; }
else
for(I=0,A-=0x4000;I<ROMBanks;I++)
if(ROMMap[I][A]==Cheats[J].Orig) ROMMap[I][A]=Cheats[J].Value;
}
}
if(ROMBanks<3) ROMMask=0;
else { for(I=1;I<ROMBanks;I<<=1);ROMMask=I-1;ROMBank=1; }
if(!RAMMap[0]) RAMMask=0;
else { for(I=1;I<RAMBanks;I<<=1);RAMMask=I-1;RAMBank=0; }
if(RAMMap[0]) Page[5]=RAMMap[0];
if(ROMMap[1]) Page[2]=ROMMap[1];
Page[3]=Page[2]+0x2000;
IPeriod=VPeriod/154;
ChrGen=RAM+0x8800;BgdTab=WndTab=RAM+0x9800;
LCDCONT=0x81;LCDSTAT=0x00;
CURLINE=0x00;CMPLINE=0xFF;
IFLAGS=ISWITCH=0xE0;
TIMECNT=TIMEMOD=0x01;
TIMEFRQ=0xF8;
SIODATA=0x00;
SIOCONT=0x7E;
SIOBuf=SIOFlag=0x00;
for(I=0;I<4;I++) SPal0[I]=SPal1[I]=BPal[I]=I;
BGRDPAL=SPR0PAL=SPR1PAL=0xE4;
if (!InitMachine())
return 0;
InitMachineDone=1;
ResetZ80(&R);Exit_PC=Z80(R);
return(1);
}
void TrashGB(void)
{
FILE *F;
int I;
if (InitMachineDone)
{
//TrashMachine ();
if(Verbose) printf("EXITED at PC = %Xh.\n",Exit_PC);
}
if(SaveName&&((RAM[0x0147]==3)||(RAM[0x0147]==6)))
{
if(Verbose) printf("\nOpening %s...",SaveName);
if(F=fopen(SaveName,"wb"))
{
if(Verbose) printf("writing...");
I=RAM[0x0147]==3? 0x2000:0x0200;
I=(fwrite(RAMMap[0]? RAMMap[0]:Page[5],1,I,F)==I);
if(Verbose) puts(I? "OK":"FAILED");
fclose(F);
}
else if(Verbose) puts("FAILED");
}
//-PG CHANGE-if(SaveName) free(SaveName);
if(RAM) free(RAM);
for(I=1;ROMMap[I];I++) free(ROMMap[I]);
for(I=0;RAMMap[I];I++) free(RAMMap[I]);
}
word Interrupt(void)
{
static byte UCount=1;
register byte J;
unsigned tmp;
DIVREG++;SprFlag|=LCDCONT&0x02;J=0x00;
/* Setting HBlank state */
if(CURLINE<144) { LCDSTAT&=0xFC;J|=0x08; }
/* Generating VBlank interrupt */
if((CURLINE==144)&&(LCDCONT&0x80))
{
LCDSTAT=(LCDSTAT&0xFC)|0x01;J|=0x10;
if(ISWITCH&VBL_IFLAG) IFLAGS|=VBL_IFLAG;
}
if(LineDelay)
{
if(!UCount&&(CURLINE<144)) RefreshLine(CURLINE);
CURLINE=(CURLINE>=153)? 0:CURLINE+1;
if(CURLINE!=CMPLINE) LCDSTAT&=0xFB;
else { LCDSTAT|=0x04;J|=0x40; }
}
else
{
if(CURLINE!=CMPLINE) LCDSTAT&=0xFB;
else { LCDSTAT|=0x04;J|=0x40; }
CURLINE=(CURLINE>=153)? 0:CURLINE+1;
if(!UCount&&(CURLINE<144)) RefreshLine(CURLINE);
}
/* If end of frame reached... */
if(CURLINE==144)
{
if(UCount) UCount--;
else
{
if(SprFlag&&(LCDCONT&0x80)) RefreshSprites();
RefreshScreen();SprFlag=0;UCount=UPeriod;
}
}
/* Generating LCD controller interrupt */
if((J&LCDSTAT)&&(ISWITCH&LCD_IFLAG)&&(LCDCONT&0x80)) IFLAGS|=LCD_IFLAG;
/* Generating timer interrupt */
if(TIMEFRQ&0x04)
{
TimerTestParam+=TimerRecurParam;
if (TimerTestParam&0xFFFF0000)
{
tmp=TIMECNT+(TimerTestParam>>16);
TimerTestParam&=0x0000FFFF;
if (tmp&0xFFFFFF00)
{
TIMECNT=TIMEMOD;
if(ISWITCH&TIM_IFLAG) IFLAGS|=TIM_IFLAG;
}
else
TIMECNT=tmp;
}
}
if(CURLINE==144)
{
/* Generating serial IO interrupt */
if(SIOFlag&0x01)
{
SIOFlag&=0xFE;SIOCONT&=0x7F;
if(ISWITCH&SIO_IFLAG) IFLAGS|=SIO_IFLAG;
}
/* Updating joystick */
J=JOYPAD|0xCF;JoyState=Joystick();
if(!(J&0x10)) JOYPAD=J&(JoyState|0xF0);
if(!(J&0x20)) JOYPAD=J&((JoyState>>4)|0xF0);
}
/* Determining interrupt address */
if(IFLAGS&EXT_IFLAG) { IMask=EXT_IFLAG;return(0x0060); }
if(IFLAGS&SIO_IFLAG) { IMask=SIO_IFLAG;return(0x0058); }
if(IFLAGS&TIM_IFLAG) { IMask=TIM_IFLAG;return(0x0050); }
if(IFLAGS&LCD_IFLAG) { IMask=LCD_IFLAG;return(0x0048); }
if(IFLAGS&VBL_IFLAG) { IMask=VBL_IFLAG;return(0x0040); }
return(0xFFFF);
}
int AddCheat(char *Cheat)
{
static char Digits[]="0123456789ABCDEF";
int X1,X2;
if(CheatCount>=MAXCHEAT) return(0);
else
{
if((Cheat[3]!='-')||(Cheat[7]!='-')) return(0);
X1=strchr(Digits,toupper(Cheat[0]))-Digits;
X2=strchr(Digits,toupper(Cheat[1]))-Digits;
if((X1<0)||(X2<0)) return(0);
else Cheats[CheatCount].Value=X1*16+X2;
X1=strchr(Digits,toupper(Cheat[4]))-Digits;
X2=strchr(Digits,toupper(Cheat[5]))-Digits;
if((X1<0)||(X2<0)) return(0);
else Cheats[CheatCount].Address=X1*16+X2;
X1=strchr(Digits,toupper(Cheat[6]))-Digits;
X2=strchr(Digits,toupper(Cheat[2]))-Digits;
if((X1<0)||(X2<0)) return(0);
else Cheats[CheatCount].Address+=256*((15-X1)*16+X2);
X1=strchr(Digits,toupper(Cheat[10]))-Digits;
X2=strchr(Digits,toupper(Cheat[8]))-Digits;
if((X1<0)||(X2<0)) return(0);
X1=~(16*X2+X1);
X1=((X1>>2)&0x3F)|((X1<<6)&0xC0);
Cheats[CheatCount].Orig=X1^0x45;
if(Cheats[CheatCount].Address>=0x8000) return(0);
CheatCount++;return(1);
}
}