⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gb.c

📁 gameboy游戏模拟器,COMMON.H CONV.C DASM.C DEBUG.C FILE_ID.DIZ FMFREQS.C FMFREQS.H GB.C GB.H GBLIST.C HEL
💻 C
📖 第 1 页 / 共 2 页
字号:

  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];
  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);
    J=(RAM[0x0149]&0x03)*2;J=J? (1<<(J-1)):0;
    printf("  RAM Size: %dkB\n",J);

    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)
    {
      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");
    }
  }
  else SaveName=NULL;

  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;
    }
  }

  IPeriod=VPeriod*256/(154*11);
  if(SndName)
  {
    if(Verbose) printf("Logging soundtrack to %s...",SndName);
    SndStream=fopen(SndName,"wb");
    if(Verbose) puts(SndStream? "OK":"FAILED");
    if(SndStream)
    {
     fprintf(SndStream,"GameBoy Soundtrack File 1.1\032");
     I=154*11*IFreq;
     fputc (I&255,SndStream);
     fputc (I>>8,SndStream);
     fputc (I>>16,SndStream);
     fputc (I>>24,SndStream);
     for (I=4;I<64;++I)
      fputc (0,SndStream);
    }
  }

  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; }

  ResetGB ();

  if (!InitMachine())
   return 0;
  InitMachineDone=1;

  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)   
  {
    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");
  }

  if(RAM) free(RAM);
  for(I=1;ROMMap[I];I++) free(ROMMap[I]);
  for(I=0;RAMMap[I];I++) free(RAMMap[I]);
  if(SndName&&SndStream)
  {
   fputc (0xF0,SndStream);
   fclose(SndStream);
  }
}

int MachineInterrupt (void);
word Interrupt(void)
{
  static byte LCDStates[11] = { 2,2,3,3,3,3,0,0,0,0,0 };
  static byte LCount=0;
  static byte UCount=1;
  static byte ACount=0;
  static byte dorefresh=1;
  byte J,I;

  ++NumInts;

  DIVREG++;LCount=(LCount+1)%11;
  if(CURLINE<144) LCDSTAT=(LCDSTAT&0xFC)|LCDStates[LCount];

  switch(LCount)
  {
    case 0:
      /* Proceeding with line refresh */
      break;
    case 2:
      /* Generating VBlank interrupt */
      if(CURLINE==144)
        if((ISWITCH&VBL_IFLAG)&&(LCDCONT&0x80))
        { IFLAGS=IMask=VBL_IFLAG;return(0x0040); }
      return(0xFFFF);
    case 5:
      /* Generate serial IO interrupt */
      if(SIOCount)
      {
        if (!--SIOCount)
        {
         SIOCONT&=0x7F;
         if(ISWITCH&SIO_IFLAG)
         { IFLAGS=IMask=SIO_IFLAG; return 0x0058; }
        }
      }
      return 0xFFFF;
    case 7:
      /* Generating HBlank interrupt */
      if((LCDSTAT&0x08)&&(CURLINE<144))
        if((ISWITCH&LCD_IFLAG)&&(LCDCONT&0x80))
        { IFLAGS=IMask=LCD_IFLAG;return(0x0048); }
      return(0xFFFF);
    case 10:
      /* Generating timer interrupt */
      if(TIMEFRQ&0x04)
      {
       TCount+=TStep;
       if(TCount&0xFFFF0000)
       {
        unsigned L;
        L=TIMECNT+(TCount>>16);
        TCount&=0x0000FFFF;
        if(L&0xFFFFFF00)
        {
          TIMECNT=TIMEMOD;
          if(ISWITCH&TIM_IFLAG)
          { IFLAGS=IMask=TIM_IFLAG;return 0x0050; }
        }
        else TIMECNT=L;
       }
       return 0xFFFF;
      }
    default:
      /* Only LCD state had to be changed */
      return(0xFFFF);
  }

  /* Checking for line coincidence and refreshing screen */
  J=0;
  if(LineDelay)
  {
    if(dorefresh&&(CURLINE<144)) RefreshLine(CURLINE);
    CURLINE=(CURLINE+1)%154;
    if(CURLINE!=CMPLINE) LCDSTAT&=0xFB;
    else { LCDSTAT|=0x04;J|=0x40; }
  }
  else
  {
    if(CURLINE!=CMPLINE) LCDSTAT&=0xFB;
    else { LCDSTAT|=0x04;J|=0x40; }
    CURLINE=(CURLINE+1)%154;
    if(dorefresh&&(CURLINE<144)) RefreshLine(CURLINE);
  }

  /* If end of frame reached... */
  if(CURLINE==144)
  {
    /* Set VBlank state */
    LCDSTAT=(LCDSTAT&0xFC)|0x01;J|=0x10;

    /* Update joystick */
    JoyState=Joystick();

    /* Autofire emulation */
    ACount=(ACount+1)&0x07;
    if(ACount>3)
    {
      if(AutoA) JoyState|=0x10;
      if(AutoB) JoyState|=0x20;
    }

    /* Assign value to JOYPAD */
    I=JOYPAD|0xCF;
    if(!(I&0x10)) JOYPAD=I&(JoyState|0xF0);
    if(!(I&0x20)) JOYPAD=I&((JoyState>>4)|0xF0);

    /* Refresh screen if needed */
    if (dorefresh)
      RefreshScreen();

    /* Sync the GB emulation */
    switch (MachineInterrupt ())
    {
     case 0:  if (UPeriod==0)
              {
               dorefresh=0;
               break;
              }
     case 1:  if (UPeriod==0)
              {
               dorefresh=1;
               break;
              }
     default: if (!--UCount)
              {
               UCount=UPeriod;
               dorefresh=1;
              }
              else
               dorefresh=0;
              break;
    }
  }

  /* Generating LCD controller interrupt */
  if((J&LCDSTAT)&&(ISWITCH&LCD_IFLAG)&&(LCDCONT&0x80)) IFLAGS|=LCD_IFLAG;

  /* 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); }

  /* No interrupt */
  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);
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -