/**************************************************************************** * Genesis Plus 1.2a * * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * * 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 * * Information in this module was gleaned from * http://en.wikibooks.org/wiki/Genesis_Programming ***************************************************************************/ #include "shared.h" #include "font.h" #include "rominfo.h" #define MAXCOMPANY 64 /*** ROM Information ***/ #define ROMCONSOLE 256 #define ROMCOPYRIGHT 272 #define ROMDOMESTIC 288 #define ROMWORLD 336 #define ROMTYPE0 384 #define ROMTYPE1 385 #define ROMPRODUCT 386 #define ROMCHECKSUM 398 #define ROMIOSUPPORT 400 #define ROMROMSTART 416 #define ROMROMEND 420 #define ROMRAMINFO 424 #define ROMRAMSTART 436 #define ROMRAMEND 440 #define ROMMODEMINFO 444 #define ROMMEMO 456 #define ROMCOUNTRY 496 #define P3BUTTONS 1 #define P6BUTTONS 2 #define PKEYBOARD 4 #define PPRINTER 8 #define PBALL 16 #define PFLOPPY 32 #define PACTIVATOR 64 #define PTEAMPLAYER 128 #define PMSYSTEMPAD 256 #define PSERIAL 512 #define PTABLET 1024 #define PPADDLE 2048 #define PCDROM 4096 #define PMOUSE 8192 typedef struct { char companyid[6]; char company[30]; } COMPANYINFO; typedef struct { char pID[2]; char pName[21]; } PERIPHERALINFO; int peripherals; int checksumok; ROMINFO rominfo; uint16 GetRealChecksum (); /*************************************************************************** * Genesis ROM Manufacturers * * Based on the document provided at * http://www.zophar.net/tech/files/Genesis_ROM_Format.txt ***************************************************************************/ COMPANYINFO companyinfo[MAXCOMPANY] = { {"ACLD", "Ballistic"}, {"RSI", "Razorsoft"}, {"SEGA", "SEGA"}, {"TREC", "Treco"}, {"VRGN", "Virgin Games"}, {"WSTN", "Westone"}, {"10", "Takara"}, {"11", "Taito or Accolade"}, {"12", "Capcom"}, {"13", "Data East"}, {"14", "Namco or Tengen"}, {"15", "Sunsoft"}, {"16", "Bandai"}, {"17", "Dempa"}, {"18", "Technosoft"}, {"19", "Technosoft"}, {"20", "Asmik"}, {"22", "Micronet"}, {"23", "Vic Tokai"}, {"24", "American Sammy"}, {"29", "Kyugo"}, {"32", "Wolfteam"}, {"33", "Kaneko"}, {"35", "Toaplan"}, {"36", "Tecmo"}, {"40", "Toaplan"}, {"42", "UFL Company Limited"}, {"43", "Human"}, {"45", "Game Arts"}, {"47", "Sage's Creation"}, {"48", "Tengen"}, {"49", "Renovation or Telenet"}, {"50", "Electronic Arts"}, {"56", "Razorsoft"}, {"58", "Mentrix"}, {"60", "Victor Musical Industries"}, {"69", "Arena"}, {"70", "Virgin"}, {"73", "Soft Vision"}, {"74", "Palsoft"}, {"76", "Koei"}, {"79", "U.S. Gold"}, {"81", "Acclaim/Flying Edge"}, {"83", "Gametek"}, {"86", "Absolute"}, {"87", "Mindscape"}, {"93", "Sony"}, {"95", "Konami"}, {"97", "Tradewest"}, {"100", "T*HQ Software"}, {"101", "Tecmagik"}, {"112", "Designer Software"}, {"113", "Psygnosis"}, {"119", "Accolade"}, {"120", "Code Masters"}, {"125", "Interplay"}, {"130", "Activision"}, {"132", "Shiny & Playmates"}, {"144", "Atlus"}, {"151", "Infogrames"}, {"161", "Fox Interactive"}, {"177", "Ubisoft"}, {"239", "Disney Interactive"}, {"---", "Unknown"} }; /*************************************************************************** * Genesis Peripheral Information * * Based on the document provided at * http://www.zophar.net/tech/files/Genesis_ROM_Format.txt ***************************************************************************/ PERIPHERALINFO peripheralinfo[14] = { {"J", "3-Button Joypad"}, {"6", "6-button Joypad"}, {"K", "Keyboard"}, {"P", "Printer"}, {"B", "Control Ball"}, {"F", "Floppy Drive"}, {"L", "Activator"}, {"4", "Team Player"}, {"0", "MS Joypad"}, {"R", "RS232C Serial"}, {"T", "Tablet"}, {"V", "Paddle"}, {"C", "CD-ROM"}, {"M", "Mega Mouse"} }; /**************************************************************************** * getcompany * * Try to determine which company made this rom * * Ok, for some reason there's no standard for this. * It seems that there can be pretty much anything you like following the * copyright (C) symbol! ****************************************************************************/ int getcompany () { char *s; int i; char company[10]; for (i = 3; i < 8; i++) company[i - 3] = rominfo.copyright[i]; company[5] = 0; /** OK, first look for a hyphen * Capcom use T-12 for example */ s = strstr (company, "-"); if (s != NULL) { s++; strcpy (company, s); } /** Strip any trailing spaces **/ for (i = strlen (company) - 1; i >= 0; i--) if (company[i] == 32) company[i] = 0; if (strlen (company) == 0) return MAXCOMPANY - 1; for (i = 0; i < MAXCOMPANY - 1; i++) { if (!(strncmp (company, companyinfo[i].companyid, strlen (company)))) return i; } return MAXCOMPANY - 1; } /*************************************************************************** * getrominfo * * Pass a pointer to the ROM base address. ***************************************************************************/ void getrominfo (char *romheader) { int i; memset (&rominfo, 0, sizeof (ROMINFO)); memcpy (&rominfo.consoletype, romheader + ROMCONSOLE, 16); memcpy (&rominfo.copyright, romheader + ROMCOPYRIGHT, 16); memcpy (&rominfo.domestic, romheader + ROMDOMESTIC, 48); memcpy (&rominfo.international, romheader + ROMWORLD, 48); memcpy (&rominfo.ROMType, romheader + ROMTYPE0, 2); memcpy (&rominfo.product, romheader + ROMPRODUCT, 12); memcpy (&rominfo.checksum, romheader + ROMCHECKSUM, 2); memcpy (&rominfo.io_support, romheader + ROMIOSUPPORT, 16); memcpy (&rominfo.romstart, romheader + ROMROMSTART, 4); memcpy (&rominfo.romend, romheader + ROMROMEND, 4); memcpy (&rominfo.RAMInfo, romheader + ROMRAMINFO, 12); memcpy (&rominfo.ramstart, romheader + ROMRAMSTART, 4); memcpy (&rominfo.ramend, romheader + ROMRAMEND, 4); memcpy (&rominfo.modem, romheader + ROMMODEMINFO, 12); memcpy (&rominfo.memo, romheader + ROMMEMO, 40); memcpy (&rominfo.country, romheader + ROMCOUNTRY, 16); checksumok = (GetRealChecksum ((char *) cart_rom + 512, genromsize - 512) == rominfo.checksum); peripherals = 0; for (i = 0; i < 14; i++) { if (rominfo.io_support[i] == peripheralinfo[i].pID[0]) peripherals |= (1 << i); } if (peripherals & P6BUTTONS) pad_type = DEVICE_6BUTTON; else pad_type = DEVICE_3BUTTON; } /*************************************************************************** * Show rom info screen ***************************************************************************/ /* Automatically fixing the checksum is not a cool idea * This should be user switchable, or at least only applied * when genromsize == ( romend - romstart ) if(realchecksum != (rominfo.checksum)) { sprintf(msg, "WARNING: Possible hacked ROM loaded!"); write_font( 10, 224, msg); cart_rom[0x18e] = realchecksum >> 8; cart_rom[0x18f] = realchecksum & 0xff; sprintf(msg, "Checksum corrected to %04x", realchecksum); write_font( 10, 248, msg); } */ void showrominfo () { int ypos; u8 i,j,quit,redraw,max; char msg[128]; short p; signed char a; uint16 realchecksum = GetRealChecksum (((uint8 *) cart_rom) + 0x200, genromsize - 0x200); quit = 0; j = 0; redraw = 1; /*** Remove any still held buttons ***/ while(PAD_ButtonsHeld(0)) VIDEO_WaitVSync(); max = 14; for (i = 0; i < 14; i++) { if ((char) rominfo.io_support[i] == peripheralinfo[i].pID[0]) max ++; } while (quit == 0) { if (redraw) { ClearScreen (); ypos = 134; WriteCentre(ypos, "ROM Header Information"); ypos += 2*fheight; for (i=0; i<8; i++) { switch (i+j) { case 0: sprintf (msg, "Console type: %s", rominfo.consoletype); break; case 1: sprintf (msg, "Copyright: %s", rominfo.copyright); break; case 2: sprintf (msg, "Company: %s", companyinfo[getcompany ()].company); break; case 3: sprintf (msg, "Game Domestic Name:"); break; case 4: sprintf(msg, " %s",rominfo.domestic); break; case 5: sprintf (msg, "Game International Name:"); break; case 6: sprintf(msg, " %s",rominfo.international); break; case 7: sprintf (msg, "Type - %s : %s", rominfo.ROMType, strcmp (rominfo.ROMType, "AI") ? "Game" : "Educational"); break; case 8: sprintf (msg, "Product - %s", rominfo.product); break; case 9: sprintf (msg, "Checksum - %04x (%04x) (%s)", rominfo.checksum, realchecksum, rominfo.checksum == realchecksum ? "Good" : "Bad"); break; case 10: sprintf (msg, "ROM end: 0x%06X", rominfo.romend); break; case 11: if (sram.detected) sprintf (msg, "External RAM start: 0x%06X", rominfo.ramstart); else sprintf (msg, "External RAM start: UNDETECTED"); break; case 12: if (sram.detected) sprintf (msg, "External RAM end : 0x%06X", rominfo.ramend); else sprintf (msg, "External RAM end : UNDETECTED"); break; case 13: if (region_code == REGION_USA) sprintf (msg, "Region - %s (USA)", rominfo.country); else if (region_code == REGION_EUROPE) sprintf (msg, "Region - %s (EUR)", rominfo.country); else if (region_code == REGION_JAPAN_NTSC) sprintf (msg, "Region - %s (JAP)", rominfo.country); else if (region_code == REGION_JAPAN_PAL) sprintf (msg, "Region - %s (JPAL)", rominfo.country); break; default: sprintf (msg, "Supports - %s", peripheralinfo[i+j-14].pName); break; } write_font (100, ypos, msg); ypos += fheight; } ypos += fheight; WriteCentre (ypos, "Press A to Continue"); SetScreen (); } p = PAD_ButtonsDown (0); a = PAD_StickY (0); redraw = 0; if ((j<(max-8)) && ((p & PAD_BUTTON_DOWN) || (a < -70))) {redraw = 1; j++;} if ((j>0) && ((p & PAD_BUTTON_UP) || (a > 70))) {redraw = 1; j--;} if (p & PAD_BUTTON_A) quit = 1; if (p & PAD_BUTTON_B) quit = 1; } } /* * softdev - New Checksum Calculation */ uint16 GetRealChecksum (uint8 * rom, int length) { int i; uint16 checksum = 0; for (i = 0; i < length; i += 2) { checksum += (uint16) rom[i]; checksum += (uint16) rom[i + 1] << 8; } return checksum; }