home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / AmigaVGB / GB.c < prev    next >
C/C++ Source or Header  |  2000-07-07  |  18KB  |  583 lines

  1. /** VGB: portable GameBoy emulator ***************************/
  2. /**                                                         **/
  3. /**                           GB.c                          **/
  4. /**                                                         **/
  5. /** This file contains the portable part of the GameBoy     **/
  6. /** hardware emulation. See GB.h for #defines related to    **/
  7. /** drivers and GameBoy hardware.                           **/
  8. /**                                                         **/
  9. /** Copyright (C) Marat Fayzullin 1995,1996                 **/
  10. /**     You are not allowed to distribute this software     **/
  11. /**     commercially. Please, notify me, if you make any    **/   
  12. /**     changes to this file.                               **/
  13. /*************************************************************/
  14.  
  15. #include "GB.h"
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <ctype.h>
  20.  
  21. byte Verbose    = 1;     /* Verboseness level                            */
  22.  
  23. byte *RAM,*Page[8];      /* RAM and pointers to Z80 address space 8x8kB) */
  24.  
  25. int  VPeriod    = 6000;  /* Number of Z80 cycles between VBlanks         */
  26. byte UPeriod    = 1;     /* Number of VBlanks per screen update          */
  27. byte LineDelay  = 0;     /* When 1, CMPLINE interrupts are delayed       */
  28. byte CheckCRC   = 1;     /* When 1, VGB checks cartridge CRC on loading  */
  29. byte AutoA      = 0;     /* When 1, autofire emulation for button A      */
  30. byte AutoB      = 0;     /* When 1, autofire emulation for button B      */
  31.  
  32. char *SaveName  = NULL;  /* .sav file name                               */
  33.  
  34. char *SndName   = NULL;  /* Soundtrack log file                          */
  35. FILE *SndStream = NULL;
  36.  
  37. struct                   /* Cheat list to be filled before StartGB()     */
  38. {                        /* is called                                    */
  39.   byte Value,Orig;
  40.   word Address;
  41. } Cheats[MAXCHEAT];
  42. int CheatCount  = 0;     /* Number of cheats in the list                 */
  43.  
  44. byte SIOBuf;             /* Next byte to output via the serial line      */
  45. byte SIOFlag;            /* Bit0 -> SIO interrupt should be generated    */
  46.                          /* Bit1 -> Data should be sent out              */
  47.  
  48. byte JoyState;           /* Joystick state: START.SELECT.B.A.D.U.L.R     */
  49.  
  50. byte IMask;              /* A mask to reset an event bit in IFLAGS       */
  51.  
  52. byte MBCType;            /* MBC type: 1 for MBC2, 0 for MBC1             */
  53. byte *ROMMap[256];       /* Addresses of ROM banks                       */
  54. byte ROMBank;            /* Number of ROM bank currently used            */
  55. byte ROMMask;            /* Mask for the ROM bank number                 */
  56. int  ROMBanks;           /* Total number of ROM banks                    */
  57. byte *RAMMap[256];       /* Addresses of RAM banks                       */ 
  58. byte RAMBank;            /* Number of RAM bank currently used            */
  59. byte RAMMask;            /* Mask for the RAM bank number                 */
  60. int  RAMBanks;           /* Total number of RAM banks                    */
  61.  
  62. unsigned long TCount,TStep;  /* Timer counter and increment              */
  63.  
  64. byte BPal[4];            /* Background palette                           */
  65. byte SPal0[4],SPal1[4];  /* Sprite palettes                              */
  66.  
  67. byte *ChrGen;            /* Character generator                          */
  68. byte *BgdTab,*WndTab;    /* Background and window character tables       */
  69.  
  70. byte SprFlag;            /* <>0: sprites were enabled during the frame   */
  71.  
  72. /*** Following are some known manufacturer codes *************************/
  73. struct { word Code;char *Name; } Companies[] =
  74. {
  75.   { 0x3301,"Nintendo"  },{ 0x7901,"Accolade"  },{ 0xA400,"Konami"    },
  76.   { 0x6701,"Ocean"     },{ 0x5601,"LJN"       },{ 0x9900,"ARC?"      },
  77.   { 0x0101,"Nintendo"  },{ 0x0801,"Capcom"    },{ 0x0100,"Nintendo"  },
  78.   { 0xBB01,"SunSoft"   },{ 0xA401,"Konami"    },{ 0xAF01,"Namcot?"   },
  79.   { 0x4901,"Irem"      },{ 0x9C01,"Imagineer" },{ 0xA600,"Kawada?"   },
  80.   { 0xB101,"Nexoft"    },{ 0x5101,"Acclaim"   },{ 0x6001,"Titus"     },
  81.   { 0xB601,"HAL"       },{ 0x3300,"Nintendo"  },{ 0x0B00,"Coconuts?" },
  82.   { 0x5401,"Gametek"   },{ 0x7F01,"Kemco?"    },{ 0xC001,"Taito"     },
  83.   { 0xEB01,"Atlus"     },{ 0xE800,"Asmik?"    },{ 0xDA00,"Tomy?"     },
  84.   { 0xB100,"ASCII?"    },{ 0xEB00,"Atlus"     },{ 0xC000,"Taito"     },
  85.   { 0x9C00,"Imagineer" },{ 0xC201,"Kemco?"    },{ 0xD101,"Sofel?"    },
  86.   { 0x6101,"Virgin"    },{ 0xBB00,"SunSoft"   },{ 0xCE01,"FCI?"      },
  87.   { 0xB400,"Enix?"     },{ 0xBD01,"Imagesoft" },{ 0x0A01,"Jaleco?"   },
  88.   { 0xDF00,"Altron?"   },{ 0xA700,"Takara?"   },{ 0xEE00,"IGS?"      },
  89.   { 0x8300,"Lozc?"     },{ 0x5001,"Absolute?" },{ 0xDD00,"NCS?"      },
  90.   { 0xE500,"Epoch?"    },{ 0xCB00,"VAP?"      },{ 0x8C00,"Vic Tokai" },
  91.   { 0xC200,"Kemco?"    },{ 0xBF00,"Sammy?"    },
  92.   { 0x1800,"Hudson Soft"    },{ 0xCA01,"Palcom/Ultra" },
  93.   { 0xCA00,"Palcom/Ultra"   },{ 0xC500,"Data East?" },
  94.   { 0xA900,"Technos Japan?" },{ 0xD900,"Banpresto?" },
  95.   { 0x7201,"Broderbund?"    },{ 0x7A01,"Triffix Entertainment?" },
  96.   { 0xE100,"Towachiki?"     },{ 0x9300,"Tsuburava?" },
  97.   { 0xC600,"Tonkin House?"  },{ 0xCE00,"Pony Canyon" },
  98.   { 0x7001,"Infogrames?"    },{ 0x8B01,"Bullet-Proof Software?" },
  99.   { 0x5501,"Park Place?"    },{ 0xEA00,"King Records?" },
  100.   { 0x5D01,"Tradewest?"     },{ 0x6F01,"ElectroBrain?" },
  101.   { 0xAA01,"Broderbund?"    },{ 0xC301,"SquareSoft" },
  102.   { 0x5201,"Activision?"    },{ 0x5A01,"Bitmap Brothers/Mindscape" },
  103.   { 0x5301,"American Sammy" },{ 0x4701,"Spectrum Holobyte" },
  104.   { 0x1801,"Hudson Soft"},{ 0x0000,NULL }
  105. };
  106.  
  107. void DoWrite(word A,byte V);
  108.  
  109. byte M_RDMEM(register word A)
  110. { return(Page[A>>13][A&0x1FFF]); }
  111.  
  112. void M_WRMEM(register word A,register byte V)
  113. {
  114.  
  115.   if(A>0xFEFF) DoWrite(A,V);
  116.   else if(A>0x7FFF) Page[A>>13][A&0x1FFF]=V;
  117.        else
  118.  
  119.   switch(A&0xE000)
  120.   {
  121.     case 0xC000:
  122.     case 0x8000: RAM[A]=V;return;
  123.     case 0xA000: Page[5][A&0x1FFF]=V;return;
  124.     case 0xE000: DoWrite(A,V);return;
  125.     case 0x2000:
  126.       if(MBCType&&((A&0xFF00)!=0x2100)) return;
  127.       V&=ROMMask;
  128.       if(!V) V++;
  129.       if(ROMMask&&(V!=ROMBank))
  130.       {
  131.         ROMBank=V;
  132.         Page[2]=ROMMap[V]? ROMMap[V]:RAM+0x4000;
  133.         Page[3]=Page[2]+0x2000;
  134.         if(Verbose&0x08) printf("ROM: Bank %d selected\n",V);
  135.       }
  136.       return;
  137.     case 0x4000:
  138.       V&=RAMMask;
  139.       if(RAMMask&&!MBCType&&(RAMBank!=V))
  140.       {
  141.         RAMBank=V;
  142.         Page[5]=RAMMap[V]? RAMMap[V]:RAM+0xA000;
  143.         if(Verbose&0x08) printf("RAM: Bank %d selected\n",V);
  144.       }
  145.       return;
  146.     case 0x0000:
  147.     case 0x6000:
  148.       if(Verbose&0x02) printf("Wrote %Xh to ROM at %Xh\n",V,A);
  149.       return;
  150.   }
  151. }
  152.  
  153. void DoWrite(register word A,register byte V)
  154. {
  155.   static unsigned long TPFreqs[] = { 4096,262144,65536,16384 };
  156.   register byte *P;
  157.  
  158.   switch(A)
  159.   {
  160.     case 0xFF00: JOYPAD=0xCF|V;
  161.                  if(!(V&0x20)) JOYPAD&=(JoyState>>4)|0xF0;
  162.                  if(!(V&0x10)) JOYPAD&=JoyState|0xF0; 
  163.                  return;
  164.     case 0xFF01: SIOBuf=V;SIOFlag|=0x02;return;
  165.     case 0xFF02: if(V&0x80)
  166.                  {
  167.                    if(SIOFlag&0x02? SIOSend(SIOBuf):SIOReceive(&SIODATA))
  168.                      SIOFlag|=0x01;
  169.                    SIOFlag=(SIOFlag&0xFD);
  170.                  }
  171.                  V|=0x7E; 
  172.                  break;
  173.     case 0xFF07: TStep=(TPFreqs[V&0x03]<<16)/(154*60);
  174.                  V|=0xF8;break;
  175.     case 0xFF0F: V&=0x1F;break;
  176.     case 0xFFFF: V&=0x1F;break;
  177.     case 0xFF46: P=RAM+0xFE00;A=(word)V<<8;
  178.                  for(V=0;V<0xA0;V++) *P++=M_RDMEM(A++);
  179.                  return;
  180.     case 0xFF41: V=(V&0xF8)|(LCDSTAT&0x07);
  181.                  break;
  182.     case 0xFF40: ChrGen=RAM+(V&0x10? 0x8000:0x8800);
  183.                  BgdTab=RAM+(V&0x08? 0x9C00:0x9800);
  184.                  WndTab=RAM+(V&0x40? 0x9C00:0x9800);
  185.                  break;
  186.     case 0xFF44: V=0;break;
  187.     case 0xFF47: BPal[0]=V&0x03;
  188.                  BPal[1]=(V&0x0C)>>2;
  189.                  BPal[2]=(V&0x30)>>4;
  190.                  BPal[3]=(V&0xC0)>>6;
  191.                  break;
  192.     case 0xFF48: SPal0[0]=V&0x03;
  193.                  SPal0[1]=(V&0x0C)>>2;
  194.                  SPal0[2]=(V&0x30)>>4;
  195.                  SPal0[3]=(V&0xC0)>>6;
  196.                  break;
  197.     case 0xFF49: SPal1[0]=V&0x03;
  198.                  SPal1[1]=(V&0x0C)>>2;
  199.                  SPal1[2]=(V&0x30)>>4;
  200.                  SPal1[3]=(V&0xC0)>>6;
  201.                  break;
  202.     default:     if((A>=0xFF10)&&(A<=0xFF26))
  203.                  {
  204.                    if(SndStream)
  205.                    { fputc(A-0xFF10,SndStream);fputc(V,SndStream); }
  206.                    Sound(A-0xFF10,V);
  207.                  }
  208.   }
  209.   RAM[A]=V;
  210. }
  211.  
  212. int StartGB(char *CartName)
  213. {
  214.   static char *CartTypes[] =
  215.   {
  216.     "ROM ONLY","ROM+MBC1","ROM+MBC1+RAM",
  217.     "ROM+MBC1+RAM+BATTERY","UNKNOWN",
  218.     "ROM+MBC2","ROM+MBC2+BATTERY"
  219.   };
  220.  
  221.   int Checksum,I,J,*T;
  222.   FILE *F;
  223.   char *P,S[50];
  224.   word A;
  225.   reg R;
  226.  
  227.   /*** STARTUP CODE starts here: ***/
  228.   T=(int *)"\01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  229. #ifdef LSB_FIRST
  230.   if(*T!=1)
  231.   {
  232.     puts("********** This machine is high-endian. *********");
  233.     puts("Take #define LSB_FIRST out and compile VGB again.");
  234.     return(0);
  235.   }
  236. #else
  237.   if(*T==1)
  238.   {
  239.     puts("********* This machine is low-endian. *********");
  240.     puts("Insert #define LSB_FIRST and compile VGB again.");
  241.     return(0);
  242.   }
  243. #endif
  244.  
  245.   RAM=NULL;SaveName=NULL;SndStream=NULL;
  246.   for(I=0;I<256;I++) RAMMap[I]=ROMMap[I]=NULL;
  247.  
  248.   if(Verbose) printf("Allocating 64kB for address space...");
  249.   if(!(RAM=malloc(0x10000))) { if(Verbose) puts("FAILED");return(0); }
  250.   memset(RAM,NORAM,0x10000);
  251.   for(I=0;I<8;I++) Page[I]=RAM+I*0x2000;
  252.  
  253.   if(Verbose) printf("OK\nOpening %s...",CartName);
  254.   if(!(F=fopen(CartName,"rb")))
  255.   { if(Verbose) puts("FAILED");return(0); }
  256.  
  257.   if(Verbose) printf("reading...");
  258.   if(fread(RAM,1,0x4000,F)!=0x4000)
  259.   { if(Verbose) puts("FAILED");return(0); }
  260.  
  261.   ROMMap[0]=RAM;
  262.   ROMBanks=2<<RAM[0x0148];
  263.   RAMBanks=(RAM[0x0149]&0x03)==3? 4:0;
  264.   Checksum=((word)RAM[0x014E]<<8)+RAM[0x014F];
  265.   MBCType=RAM[0x0147]>3;
  266.  
  267.   P=NULL;
  268.   if((RAM[0x0147]==4)||(RAM[0x0147]>6)) P="Unknown ROM type";
  269.   if(P)
  270.   {
  271.     printf("\nError loading cartridge: %s\n",P);
  272.     fclose(F);return(0);
  273.   }
  274.  
  275.   if(Verbose)
  276.   {
  277.     strncpy(S,RAM+0x0134,16);S[16]='\0';
  278.     printf("OK\n  Name: %s\n",S);
  279.     printf("  Type: %s\n",CartTypes[RAM[0x0147]]);
  280.     printf("  ROM Size: %dx16kB\n",ROMBanks);
  281.     J=(RAM[0x0149]&0x03)*2;J=J? (1<<(J-1)):0;
  282.     printf("  RAM Size: %dkB\n",J);
  283.  
  284.     J=((word)RAM[0x014B]<<8)+RAM[0x014A];
  285.     for(I=0,P=NULL;!P&&Companies[I].Name;I++)
  286.       if(J==Companies[I].Code) P=Companies[I].Name;
  287.     printf("  Manufacturer ID: %Xh",J);
  288.     printf(" [%s]\n",P? P:"?");
  289.  
  290.     printf("  Version Number: %Xh\n",RAM[0x014C]);
  291.     printf("  Complement Check: %Xh\n",RAM[0x014D]);
  292.     printf("  Checksum: %Xh\n",Checksum);
  293.     J=((word)RAM[0x0103]<<8)+RAM[0x0102];
  294.     printf("  Start Address: %Xh\n",J);
  295.   }
  296.  
  297.   Checksum+=RAM[0x014E]+RAM[0x014F];
  298.   for(I=0;I<0x4000;I++) Checksum-=RAM[I];
  299.  
  300.   if(Verbose) printf("Loading %dx16kB ROM banks:\n.",ROMBanks);
  301.   for(I=1;I<ROMBanks;I++)
  302.     if(ROMMap[I]=malloc(0x4000))
  303.       if(fread(ROMMap[I],1,0x4000,F)==0x4000)
  304.       {
  305.         for(J=0;J<0x4000;J++) Checksum-=ROMMap[I][J];
  306.         if(Verbose) putchar('.');
  307.       }
  308.       else { if(Verbose) puts("READ FAILED");break; }
  309.     else { if(Verbose) puts("MALLOC FAILED");break; }
  310.  
  311.   fclose(F);if(I<ROMBanks) return(0);
  312.  
  313.   if(CheckCRC&&(Checksum&0xFFFF))
  314.   { puts("\nError loading cartridge: Checksum is wrong");return(0); }
  315.  
  316.   if(Verbose) puts("OK");
  317.  
  318.   if(RAMBanks&&!MBCType)
  319.   {
  320.     if(Verbose) printf("Allocating %dx8kB RAM banks...",RAMBanks);
  321.     for(I=0;I<RAMBanks;I++)
  322.       if(RAMMap[I]=malloc(0x2000))
  323.         memset(RAMMap[I],0,0x2000);
  324.       else
  325.       { if(Verbose) puts("FAILED");return(0); }
  326.     if(Verbose) puts("OK");
  327.   }
  328.  
  329.   if((RAM[0x0147]!=3)&&(RAM[0x0147]!=6)) SaveName=NULL;
  330.   else
  331.     if(SaveName=malloc(strlen(CartName)+10))
  332.     {
  333.       strcpy(SaveName,CartName);
  334.       if(P=strrchr(SaveName,'.')) strcpy(P,".sav");
  335.       else strcat(SaveName,".sav");
  336.  
  337.       if(Verbose) printf("Opening %s...",SaveName);
  338.       if(F=fopen(SaveName,"rb"))
  339.       {
  340.         if(Verbose) printf("reading...");
  341.         J=RAM[0x0147]==3? 0x2000:0x0200;
  342.         J=(fread(RAMMap[0]? RAMMap[0]:Page[5],1,J,F)==J);
  343.         if(Verbose) puts(J? "OK":"FAILED");
  344.         fclose(F);
  345.       }
  346.       else if(Verbose) puts("FAILED");
  347.     }
  348.  
  349.   if(CheatCount>0)
  350.   {
  351.     if(Verbose) puts("Patching cheats into the ROM code:");
  352.     for(J=0;J<CheatCount;J++)
  353.     {
  354.       A=Cheats[J].Address;
  355.       if(Verbose)
  356.         printf("  at %Xh: %Xh -> %Xh\n",A,Cheats[J].Orig,Cheats[J].Value);
  357.       if(A<0x4000)
  358.       { if(ROMMap[0][A]==Cheats[J].Orig) ROMMap[0][A]=Cheats[J].Value; }
  359.       else
  360.         for(I=0,A-=0x4000;I<ROMBanks;I++)
  361.           if(ROMMap[I][A]==Cheats[J].Orig) ROMMap[I][A]=Cheats[J].Value;
  362.     }
  363.   }
  364.  
  365.   if(SndName)
  366.   {
  367.     if(Verbose) printf("Logging soundtrack to %s...",SndName);
  368.     SndStream=fopen(SndName,"wb");
  369.     if(Verbose) puts(SndStream? "OK":"FAILED");
  370.     if(SndStream) fprintf(SndStream,"GameBoy Soundtrack File 1.0\032");
  371.   }
  372.  
  373.   if(ROMBanks<3) ROMMask=0;
  374.   else { for(I=1;I<ROMBanks;I<<=1);ROMMask=I-1;ROMBank=1; }
  375.   if(!RAMMap[0]) RAMMask=0;
  376.   else { for(I=1;I<RAMBanks;I<<=1);RAMMask=I-1;RAMBank=0; }
  377.  
  378.   if(RAMMap[0]) Page[5]=RAMMap[0];
  379.   if(ROMMap[1]) Page[2]=ROMMap[1];
  380.   Page[3]=Page[2]+0x2000;
  381.  
  382.   IPeriod=VPeriod/154/11;
  383.   TStep=32768;TCount=0;
  384.  
  385.   ChrGen=RAM+0x8800;BgdTab=WndTab=RAM+0x9800;
  386.   LCDCONT=0x81;LCDSTAT=0x00;
  387.   CURLINE=0x00;CMPLINE=0xFF;
  388.   IFLAGS=ISWITCH=0x00;
  389.   TIMECNT=TIMEMOD=0x01;
  390.   TIMEFRQ=0xF8;
  391.   SIODATA=0x00;
  392.   SIOCONT=0x7E;
  393.   SIOBuf=SIOFlag=0x00;
  394.   SprFlag=0;
  395.   JoyState=0xFF;
  396.  
  397.   for(I=0;I<4;I++) SPal0[I]=SPal1[I]=BPal[I]=I;
  398.   BGRDPAL=SPR0PAL=SPR1PAL=0xE4;
  399.  
  400.   if(Verbose) printf("RUNNING ROM CODE...\n");
  401.   ResetZ80(&R);A=Z80(R);
  402.  
  403.   if(Verbose) printf("EXITED at PC = %04Xh.\n",A); 
  404.   return(1);
  405. }
  406.  
  407. void TrashGB(void)
  408. {
  409.   FILE *F;
  410.   int I;
  411.  
  412.   if(SaveName)
  413.   {
  414.     if(Verbose) printf("\nOpening %s...",SaveName);   
  415.     if(F=fopen(SaveName,"wb"))
  416.     { 
  417.       if(Verbose) printf("writing...");
  418.       I=RAM[0x0147]==3? 0x2000:0x0200;
  419.       I=(fwrite(RAMMap[0]? RAMMap[0]:Page[5],1,I,F)==I);
  420.       if(Verbose) puts(I? "OK":"FAILED");
  421.       fclose(F);
  422.     }
  423.     else if(Verbose) puts("FAILED");
  424.     free(SaveName);
  425.   }
  426.  
  427.   if(RAM) free(RAM);
  428.   for(I=1;ROMMap[I];I++) free(ROMMap[I]);
  429.   for(I=0;RAMMap[I];I++) free(RAMMap[I]);
  430.   if(SndName&&SndStream) fclose(SndStream);
  431. }
  432.  
  433. word Interrupt(void)
  434. {
  435.   static byte LCDStates[11] = { 2,2,3,3,3,3,0,0,0,0,0 };
  436.   static byte LCount=0;
  437.   static byte UCount=1;
  438.   static byte ACount=0;
  439.   register byte J,I;
  440.  
  441.   DIVREG++;LCount=(LCount+1)%11;
  442.   if(CURLINE<144) LCDSTAT=(LCDSTAT&0xFC)|LCDStates[LCount];
  443.  
  444.   switch(LCount)
  445.   {
  446.     case 0:
  447.       /* Proceeding with line refresh */
  448.       break;
  449.     case 2:
  450.       /* Generating VBlank interrupt */
  451.       if(CURLINE==144)
  452.         if((ISWITCH&VBL_IFLAG)&&(LCDCONT&0x80))
  453.         { IFLAGS=IMask=VBL_IFLAG;return(0x0040); }
  454.       return(0xFFFF);
  455.     case 7:
  456.       /* Generating HBlank interrupt */
  457.       if((LCDSTAT&0x08)&&(CURLINE<144))
  458.         if((ISWITCH&LCD_IFLAG)&&(LCDCONT&0x80))
  459.         { IFLAGS=IMask=LCD_IFLAG;return(0x0048); }
  460.       return(0xFFFF);
  461.     default:
  462.       /* Only LCD state had to be changed */
  463.       return(0xFFFF);
  464.   }
  465.  
  466.   CURLINE=(CURLINE+1)%154;
  467.   if(!UCount&&(CURLINE<144)) RefreshLine(CURLINE);
  468.   SprFlag|=LCDCONT&0x02;
  469.  
  470.   /* Checking for line coincidence */
  471.   J=LineDelay? (CURLINE+1)%154:CURLINE;
  472.   if(J!=CMPLINE) { LCDSTAT&=0xFB;J=0x00; }
  473.   else           { LCDSTAT|=0x04;J=0x40; }
  474.  
  475.   /* If end of frame reached... */
  476.   if(CURLINE==144)
  477.   {
  478.     /* Set VBlank state */
  479.     LCDSTAT=(LCDSTAT&0xFC)|0x01;J|=0x10;
  480.  
  481.     /* Write interrupt timestamp into sound log */
  482.     if(SndStream) fputc(0xFF,SndStream);
  483.  
  484.     /* Refresh screen if needed */
  485.     if(UCount) UCount--;
  486.     else
  487.     {
  488.       if(SprFlag&&(LCDCONT&0x80)) RefreshSprites();
  489.       RefreshScreen();SprFlag=0;UCount=UPeriod;
  490.     }
  491.  
  492.     /* Generate serial IO interrupt */
  493.     if(SIOFlag&0x01)
  494.     {
  495.       SIOFlag&=0xFE;SIOCONT&=0x7F;
  496.       if(ISWITCH&SIO_IFLAG) IFLAGS|=SIO_IFLAG;
  497.     }
  498.  
  499.     /* Update joystick */
  500.     JoyState=Joystick();
  501.  
  502.     /* Autofire emulation */
  503.     ACount=(ACount+1)&0x07;
  504.     if(ACount>3)
  505.     {
  506.       if(AutoA) JoyState|=0x10;
  507.       if(AutoB) JoyState|=0x20;
  508.     }
  509.  
  510.     /* Assign value to JOYPAD */
  511.     I=JOYPAD|0xCF;
  512.     if(!(I&0x10)) JOYPAD=I&(JoyState|0xF0);
  513.     if(!(I&0x20)) JOYPAD=I&((JoyState>>4)|0xF0);
  514.   }
  515.  
  516.   /* Generating LCD controller interrupt */
  517.   if((J&LCDSTAT)&&(ISWITCH&LCD_IFLAG)&&(LCDCONT&0x80)) IFLAGS|=LCD_IFLAG;
  518.  
  519.   /* Generating timer interrupt */
  520.   if(TIMEFRQ&0x04)
  521.   {
  522.     TCount+=TStep;
  523.     if(TCount&0xFFFF0000)
  524.     {
  525.       unsigned long L;
  526.       L=TIMECNT+(TCount>>16);
  527.       TCount&=0x0000FFFF;
  528.       if(L&0xFFFFFF00)
  529.       {
  530.         TIMECNT=TIMEMOD;
  531.         if(ISWITCH&TIM_IFLAG) IFLAGS|=TIM_IFLAG;
  532.       }
  533.       else TIMECNT=L;
  534.     }
  535.   }
  536.  
  537.   /* Determining interrupt address */
  538.   if(J=IFLAGS)
  539.   {
  540.     if(J&EXT_IFLAG) { IMask=EXT_IFLAG;return(0x0060); }
  541.     if(J&SIO_IFLAG) { IMask=SIO_IFLAG;return(0x0058); }
  542.     if(J&TIM_IFLAG) { IMask=TIM_IFLAG;return(0x0050); }
  543.     if(J&LCD_IFLAG) { IMask=LCD_IFLAG;return(0x0048); }
  544.     if(J&VBL_IFLAG) { IMask=VBL_IFLAG;return(0x0040); }
  545.   }
  546.  
  547.   /* No interrupt */
  548.   return(0xFFFF);
  549.  
  550. int AddCheat(char *Cheat)
  551. {
  552.   static char Digits[]="0123456789ABCDEF";
  553.   int X1,X2;
  554.  
  555.   if(CheatCount>=MAXCHEAT) return(0);
  556.   else
  557.   {
  558.     if((Cheat[3]!='-')||(Cheat[7]!='-')) return(0);
  559.     X1=strchr(Digits,toupper(Cheat[0]))-Digits;
  560.     X2=strchr(Digits,toupper(Cheat[1]))-Digits;
  561.     if((X1<0)||(X2<0)) return(0);
  562.     else Cheats[CheatCount].Value=X1*16+X2;
  563.     X1=strchr(Digits,toupper(Cheat[4]))-Digits;
  564.     X2=strchr(Digits,toupper(Cheat[5]))-Digits;
  565.     if((X1<0)||(X2<0)) return(0);
  566.     else Cheats[CheatCount].Address=X1*16+X2;
  567.     X1=strchr(Digits,toupper(Cheat[6]))-Digits;
  568.     X2=strchr(Digits,toupper(Cheat[2]))-Digits;
  569.     if((X1<0)||(X2<0)) return(0);
  570.     else Cheats[CheatCount].Address+=256*((15-X1)*16+X2);
  571.     X1=strchr(Digits,toupper(Cheat[10]))-Digits;
  572.     X2=strchr(Digits,toupper(Cheat[8]))-Digits;
  573.     if((X1<0)||(X2<0)) return(0);
  574.     X1=~(16*X2+X1);
  575.     X1=((X1>>2)&0x3F)|((X1<<6)&0xC0);
  576.     Cheats[CheatCount].Orig=X1^0x45;
  577.  
  578.     if(Cheats[CheatCount].Address>=0x8000) return(0);
  579.     CheatCount++;return(1);
  580.   }
  581. }
  582.