| 1 | /* FCE Ultra - NES/Famicom Emulator\r |
| 2 | *\r |
| 3 | * Copyright notice for this file:\r |
| 4 | * Copyright (C) 2003 Xodnizel\r |
| 5 | *\r |
| 6 | * This program is free software; you can redistribute it and/or modify\r |
| 7 | * it under the terms of the GNU General Public License as published by\r |
| 8 | * the Free Software Foundation; either version 2 of the License, or\r |
| 9 | * (at your option) any later version.\r |
| 10 | *\r |
| 11 | * This program is distributed in the hope that it will be useful,\r |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r |
| 14 | * GNU General Public License for more details.\r |
| 15 | *\r |
| 16 | * You should have received a copy of the GNU General Public License\r |
| 17 | * along with this program; if not, write to the Free Software\r |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r |
| 19 | */\r |
| 20 | \r |
| 21 | #include <string.h>\r |
| 22 | #include <stdio.h>\r |
| 23 | \r |
| 24 | #include "types.h"\r |
| 25 | #include "x6502.h"\r |
| 26 | #include "fce.h"\r |
| 27 | #include "input.h"\r |
| 28 | #include "netplay.h"\r |
| 29 | #include "vsuni.h"\r |
| 30 | #include "state.h"\r |
| 31 | \r |
| 32 | #include "svga.h"\r |
| 33 | \r |
| 34 | #define IOPTION_GUN 0x1\r |
| 35 | #define IOPTION_SWAPDIRAB 0x2\r |
| 36 | \r |
| 37 | #define IOPTION_PREDIP 0x10\r |
| 38 | typedef struct\r |
| 39 | {\r |
| 40 | char *name;\r |
| 41 | uint64 md5partial;\r |
| 42 | int mapper;\r |
| 43 | int mirroring;\r |
| 44 | int ppu;\r |
| 45 | int ioption;\r |
| 46 | int predip;\r |
| 47 | } VSUNIENTRY;\r |
| 48 | \r |
| 49 | VSUNIENTRY *curvs;\r |
| 50 | \r |
| 51 | static uint8 DIPS=0;\r |
| 52 | uint8 vsdip=0;\r |
| 53 | \r |
| 54 | void FCEUI_VSUniToggleDIPView(void)\r |
| 55 | {\r |
| 56 | DIPS=!DIPS;\r |
| 57 | }\r |
| 58 | \r |
| 59 | void FCEU_VSUniToggleDIP(int w)\r |
| 60 | {\r |
| 61 | vsdip^=1<<w;\r |
| 62 | }\r |
| 63 | \r |
| 64 | void FCEUI_VSUniSetDIP(int w, int state)\r |
| 65 | {\r |
| 66 | if(((vsdip >> w) & 1) != state)\r |
| 67 | FCEUI_VSUniToggleDIP(w);\r |
| 68 | }\r |
| 69 | \r |
| 70 | uint8 FCEUI_VSUniGetDIPs(void)\r |
| 71 | {\r |
| 72 | return(vsdip);\r |
| 73 | }\r |
| 74 | \r |
| 75 | static uint8 secdata[2][32]=\r |
| 76 | {\r |
| 77 | {\r |
| 78 | 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,\r |
| 79 | 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,\r |
| 80 | 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,\r |
| 81 | 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00\r |
| 82 | },\r |
| 83 | {\r |
| 84 | 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,\r |
| 85 | 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,\r |
| 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r |
| 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r |
| 88 | }\r |
| 89 | };\r |
| 90 | \r |
| 91 | static uint8 *secptr;\r |
| 92 | \r |
| 93 | static uint8 VSindex;\r |
| 94 | \r |
| 95 | static DECLFR(VSSecRead)\r |
| 96 | {\r |
| 97 | switch(A)\r |
| 98 | {\r |
| 99 | case 0x5e00: VSindex=0;return X.DB;\r |
| 100 | case 0x5e01: return(secptr[(VSindex++)&0x1F]);\r |
| 101 | }\r |
| 102 | return(0x00);\r |
| 103 | }\r |
| 104 | uint8 coinon=0;\r |
| 105 | \r |
| 106 | void FCEU_VSUniCoin(void)\r |
| 107 | {\r |
| 108 | coinon=6;\r |
| 109 | }\r |
| 110 | \r |
| 111 | static int curppu;\r |
| 112 | static int64 curmd5;\r |
| 113 | \r |
| 114 | #define RP2C04_001 1\r |
| 115 | #define RP2C04_002 2\r |
| 116 | #define RP2C04_003 3\r |
| 117 | #define RP2C05_004 4\r |
| 118 | #define RCP2C03B 5\r |
| 119 | #define RC2C05_01 6\r |
| 120 | #define RC2C05_02 7\r |
| 121 | #define RC2C05_03 8\r |
| 122 | #define RC2C05_04 9\r |
| 123 | \r |
| 124 | static readfunc OldReadPPU;\r |
| 125 | static writefunc OldWritePPU[2];\r |
| 126 | \r |
| 127 | static DECLFR(A2002_Gumshoe)\r |
| 128 | {\r |
| 129 | return( (OldReadPPU(A)&~0x3F) | 0x1C);\r |
| 130 | }\r |
| 131 | \r |
| 132 | static DECLFR(A2002_Topgun)\r |
| 133 | {\r |
| 134 | return( (OldReadPPU(A)&~0x3F) | 0x1B);\r |
| 135 | }\r |
| 136 | \r |
| 137 | static DECLFR(A2002_MBJ) // Mighty Bomb Jack\r |
| 138 | {\r |
| 139 | return( (OldReadPPU(A)&~0x3F) | 0x3D);\r |
| 140 | }\r |
| 141 | \r |
| 142 | static DECLFW(B2000_2001_2C05)\r |
| 143 | {\r |
| 144 | OldWritePPU[(A&1)^1](A ^ 1, V);\r |
| 145 | }\r |
| 146 | static uint8 xevselect = 0;\r |
| 147 | static DECLFR(XevRead)\r |
| 148 | {\r |
| 149 | //printf("%04x\n",A);\r |
| 150 | if(A == 0x54FF)\r |
| 151 | {\r |
| 152 | return(0x5);\r |
| 153 | }\r |
| 154 | else if(A == 0x5678)\r |
| 155 | {\r |
| 156 | return(xevselect?0:1);\r |
| 157 | }\r |
| 158 | else if(A == 0x578F)\r |
| 159 | {\r |
| 160 | return(xevselect?0xd1:0x89);\r |
| 161 | }\r |
| 162 | else if(A == 0x5567)\r |
| 163 | {\r |
| 164 | xevselect ^=1;\r |
| 165 | return(xevselect?0x37:0x3E);\r |
| 166 | }\r |
| 167 | return(X.DB);\r |
| 168 | }\r |
| 169 | \r |
| 170 | void FCEU_VSUniSwap(uint8 *j0, uint8 *j1)\r |
| 171 | {\r |
| 172 | if(curvs->ioption & IOPTION_SWAPDIRAB)\r |
| 173 | {\r |
| 174 | uint16 t=*j0;\r |
| 175 | *j0=(*j0&0xC)|(*j1&0xF3);\r |
| 176 | *j1=(*j1&0xC)|(t&0xF3);\r |
| 177 | }\r |
| 178 | }\r |
| 179 | \r |
| 180 | void FCEU_VSUniPower(void)\r |
| 181 | {\r |
| 182 | coinon = 0;\r |
| 183 | VSindex = 0;\r |
| 184 | \r |
| 185 | if(secptr)\r |
| 186 | SetReadHandler(0x5e00,0x5e01,VSSecRead);\r |
| 187 | \r |
| 188 | if(curppu == RC2C05_04)\r |
| 189 | {\r |
| 190 | OldReadPPU = GetReadHandler(0x2002);\r |
| 191 | SetReadHandler(0x2002, 0x2002, A2002_Topgun);\r |
| 192 | }\r |
| 193 | else if(curppu == RC2C05_03)\r |
| 194 | {\r |
| 195 | OldReadPPU = GetReadHandler(0x2002);\r |
| 196 | SetReadHandler(0x2002, 0x2002, A2002_Gumshoe);\r |
| 197 | }\r |
| 198 | else if(curppu == RC2C05_02)\r |
| 199 | {\r |
| 200 | OldReadPPU = GetReadHandler(0x2002);\r |
| 201 | SetReadHandler(0x2002, 0x2002, A2002_MBJ);\r |
| 202 | }\r |
| 203 | if(curppu == RC2C05_04 || curppu == RC2C05_01 || curppu == RC2C05_03 || curppu == RC2C05_02)\r |
| 204 | {\r |
| 205 | OldWritePPU[0] = GetWriteHandler(0x2000);\r |
| 206 | OldWritePPU[1] = GetWriteHandler(0x2001);\r |
| 207 | SetWriteHandler(0x2000, 0x2001, B2000_2001_2C05);\r |
| 208 | }\r |
| 209 | if(curmd5 == 0x2d396247cf58f9faLL) /* Super Xevious */\r |
| 210 | {\r |
| 211 | SetReadHandler(0x5400,0x57FF,XevRead);\r |
| 212 | }\r |
| 213 | }\r |
| 214 | \r |
| 215 | /* Games that will probably not be supported ever(or for a long time), since they require\r |
| 216 | dual-system:\r |
| 217 | \r |
| 218 | Balloon Fight\r |
| 219 | VS Mahjong\r |
| 220 | VS Tennis\r |
| 221 | Wrecking Crew\r |
| 222 | */\r |
| 223 | \r |
| 224 | /* Games/PPU list. Information copied from MAME. ROMs are exchangable, so don't take\r |
| 225 | this list as "this game must use this PPU".\r |
| 226 | \r |
| 227 | RP2C04-001:\r |
| 228 | - Baseball\r |
| 229 | - Freedom Force\r |
| 230 | - Gradius\r |
| 231 | - Hogan's Alley\r |
| 232 | - Mach Rider (Japan, Fighting Course)\r |
| 233 | - Pinball\r |
| 234 | - Platoon\r |
| 235 | - Super Xevious\r |
| 236 | \r |
| 237 | RP2C04-002:\r |
| 238 | - Castlevania\r |
| 239 | - Ladies golf\r |
| 240 | - Mach Rider (Endurance Course)\r |
| 241 | - Raid on Bungeling Bay (Japan)\r |
| 242 | - Slalom\r |
| 243 | - Stroke N' Match Golf\r |
| 244 | - Wrecking Crew\r |
| 245 | \r |
| 246 | RP2C04-003:\r |
| 247 | - Dr mario\r |
| 248 | - Excite Bike\r |
| 249 | - Goonies\r |
| 250 | - Soccer\r |
| 251 | - TKO Boxing\r |
| 252 | \r |
| 253 | RP2c05-004:\r |
| 254 | - Clu Clu Land\r |
| 255 | - Excite Bike (Japan)\r |
| 256 | - Ice Climber\r |
| 257 | - Ice Climber Dual (Japan)\r |
| 258 | - Super Mario Bros.\r |
| 259 | \r |
| 260 | Rcp2c03b:\r |
| 261 | - Battle City\r |
| 262 | - Duck Hunt\r |
| 263 | - Mahjang\r |
| 264 | - Pinball (Japan)\r |
| 265 | - Rbi Baseball\r |
| 266 | - Star Luster\r |
| 267 | - Stroke and Match Golf (Japan)\r |
| 268 | - Super Skykid\r |
| 269 | - Tennis\r |
| 270 | - Tetris\r |
| 271 | \r |
| 272 | RC2C05-01:\r |
| 273 | - Ninja Jajamaru Kun (Japan)\r |
| 274 | \r |
| 275 | RC2C05-02:\r |
| 276 | - Mighty Bomb Jack (Japan)\r |
| 277 | \r |
| 278 | RC2C05-03:\r |
| 279 | - Gumshoe\r |
| 280 | \r |
| 281 | RC2C05-04:\r |
| 282 | - Top Gun\r |
| 283 | */\r |
| 284 | \r |
| 285 | VSUNIENTRY VSUniGames[] =\r |
| 286 | {\r |
| 287 | {"Baseball", 0x691d4200ea42be45LL, 99, 2,RP2C04_001,0},\r |
| 288 | {"Battle City", 0x8540949d74c4d0ebLL, 99, 2,RP2C04_001,0},\r |
| 289 | {"Battle City(Bootleg)",0x8093cbe7137ac031LL, 99, 2,RP2C04_001,0},\r |
| 290 | \r |
| 291 | {"Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2,RP2C05_004,IOPTION_SWAPDIRAB},\r |
| 292 | {"Dr Mario", 0xe1af09c477dc0081LL, 1, 0,RP2C04_003,IOPTION_SWAPDIRAB},\r |
| 293 | {"Duck Hunt", 0x47735d1e5f1205bbLL, 99, 2,RCP2C03B ,IOPTION_GUN},\r |
| 294 | {"Excitebike", 0x3dcd1401bcafde77LL, 99, 2,RP2C04_003,0},\r |
| 295 | {"Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2,RP2C05_004,0},\r |
| 296 | {"Freedom Force", 0xed96436bd1b5e688LL, 4, 0,RP2C04_001,IOPTION_GUN}, /* Wrong color in game select screen? */\r |
| 297 | {"Stroke and Match Golf",0x612325606e82bc66LL, 99, 2,RP2C04_002,IOPTION_SWAPDIRAB|IOPTION_PREDIP,0x01},\r |
| 298 | \r |
| 299 | {"Goonies", 0x3b0085c4ff29098eLL, 151,1,RP2C04_003,0},\r |
| 300 | {"Gradius", 0x50687ae63bdad976LL,151, 1,RP2C04_001,IOPTION_SWAPDIRAB},\r |
| 301 | {"Gumshoe", 0xb8500780bf69ce29LL, 99, 2,RC2C05_03,IOPTION_GUN},\r |
| 302 | {"Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2,RP2C04_001,IOPTION_GUN},\r |
| 303 | {"Ice Climber", 0xd21e999513435e2aLL, 99, 2,RP2C05_004,IOPTION_SWAPDIRAB},\r |
| 304 | {"Ladies Golf", 0x781b24be57ef6785LL, 99, 2,RP2C04_002,IOPTION_SWAPDIRAB|IOPTION_PREDIP,0x1},\r |
| 305 | \r |
| 306 | {"Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_002,0},\r |
| 307 | {"Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_001,0},\r |
| 308 | {"Mighty Bomb Jack", 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02,0},\r |
| 309 | {"Ninja Jajamaru Kun", 0xb26a2c31474099c0LL, 99, 2,RC2C05_01 ,IOPTION_SWAPDIRAB},\r |
| 310 | {"Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2,RP2C04_001,IOPTION_PREDIP,0x01},\r |
| 311 | {"Pinball (J)", 0x66ab1a3828cc901cLL, 99, 2,RCP2C03B,IOPTION_PREDIP,0x1},\r |
| 312 | {"Platoon", 0x160f237351c19f1fLL, 68, 1,RP2C04_001,0},\r |
| 313 | {"RBI Baseball", 0x6a02d345812938afLL, 4, 1,RP2C04_001 ,IOPTION_SWAPDIRAB},\r |
| 314 | {"Soccer", 0xd4e7a9058780eda3LL, 99, 2,RP2C04_003,IOPTION_SWAPDIRAB},\r |
| 315 | {"Star Luster", 0x8360e134b316d94cLL, 99, 2,RCP2C03B ,0},\r |
| 316 | {"Stroke and Match Golf (J)",0x869bb83e02509747LL, 99, 2,RCP2C03B,IOPTION_SWAPDIRAB|IOPTION_PREDIP,0x1},\r |
| 317 | {"Super Sky Kid", 0x78d04c1dd4ec0101LL, 4, 1,RCP2C03B ,IOPTION_SWAPDIRAB | IOPTION_PREDIP,0x20},\r |
| 318 | \r |
| 319 | {"Super Xevious", 0x2d396247cf58f9faLL, 206, 0,RP2C04_001,0},\r |
| 320 | {"Tetris", 0x531a5e8eea4ce157LL, 99, 2,RCP2C03B ,IOPTION_PREDIP,0x20},\r |
| 321 | {"Top Gun", 0xf1dea36e6a7b531dLL, 2, 0,RC2C05_04 ,0},\r |
| 322 | {"VS Castlevania", 0x92fd6909c81305b9LL, 2, 1,RP2C04_002,0},\r |
| 323 | {"VS Slalom", 0x4889b5a50a623215LL, 0, 1,RP2C04_002,0},\r |
| 324 | {"VS Super Mario Bros",0x39d8cfa788e20b6cLL, 99, 2,RP2C05_004,0},\r |
| 325 | {"VS TKO Boxing", 0x6e1ee06171d8ce3aLL,4, 1,RP2C04_003,IOPTION_PREDIP,0x00},\r |
| 326 | {0}\r |
| 327 | };\r |
| 328 | \r |
| 329 | void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring)\r |
| 330 | {\r |
| 331 | VSUNIENTRY *vs = VSUniGames;\r |
| 332 | \r |
| 333 | while(vs->name)\r |
| 334 | {\r |
| 335 | if(md5partial == vs->md5partial)\r |
| 336 | {\r |
| 337 | \r |
| 338 | if(vs->ppu < RCP2C03B) pale = vs->ppu;\r |
| 339 | //puts(vs->name);\r |
| 340 | *MapperNo = vs->mapper;\r |
| 341 | *Mirroring = vs->mirroring;\r |
| 342 | FCEUGameInfo.type = GIT_VSUNI;\r |
| 343 | FCEUGameInfo.cspecial = SIS_VSUNISYSTEM;\r |
| 344 | FCEUGameInfo.inputfc = SIFC_NONE;\r |
| 345 | curppu = vs->ppu;\r |
| 346 | curmd5 = md5partial;\r |
| 347 | \r |
| 348 | secptr = 0;\r |
| 349 | \r |
| 350 | {\r |
| 351 | static int64 tko=0x6e1ee06171d8ce3aULL, rbi=0x6a02d345812938afULL;\r |
| 352 | if(md5partial == tko)\r |
| 353 | secptr=secdata[0];\r |
| 354 | if(md5partial == rbi)\r |
| 355 | secptr = secdata[1];\r |
| 356 | }\r |
| 357 | \r |
| 358 | vsdip = 0x0;\r |
| 359 | if(vs->ioption & IOPTION_PREDIP)\r |
| 360 | {\r |
| 361 | vsdip= vs->predip;\r |
| 362 | }\r |
| 363 | if(vs->ioption & IOPTION_GUN)\r |
| 364 | {\r |
| 365 | FCEUGameInfo.input[0] = SI_ZAPPER;\r |
| 366 | FCEUGameInfo.input[1] = SI_NONE;\r |
| 367 | }\r |
| 368 | else\r |
| 369 | {\r |
| 370 | FCEUGameInfo.input[0] = FCEUGameInfo.input[1] = SI_GAMEPAD;\r |
| 371 | }\r |
| 372 | curvs = vs;\r |
| 373 | return;\r |
| 374 | }\r |
| 375 | vs++;\r |
| 376 | }\r |
| 377 | }\r |
| 378 | \r |
| 379 | #define SCREEN_WIDTH 320\r |
| 380 | #define SCREEN_OFFS 32\r |
| 381 | \r |
| 382 | void FCEU_VSUniDraw(uint8 *XBuf)\r |
| 383 | {\r |
| 384 | uint32 *dest;\r |
| 385 | int y,x;\r |
| 386 | \r |
| 387 | if(!DIPS) return;\r |
| 388 | \r |
| 389 | dest=(uint32 *)(XBuf+SCREEN_WIDTH*12+164+SCREEN_OFFS);\r |
| 390 | for(y=24;y;y--,dest+=(SCREEN_WIDTH-72)>>2)\r |
| 391 | {\r |
| 392 | for(x=72>>2;x;x--,dest++)\r |
| 393 | *dest=0;\r |
| 394 | }\r |
| 395 | \r |
| 396 | dest=(uint32 *)(XBuf+SCREEN_WIDTH*(12+4)+164+6+SCREEN_OFFS );\r |
| 397 | for(y=16;y;y--,dest+=(SCREEN_WIDTH>>2)-16)\r |
| 398 | for(x=8;x;x--)\r |
| 399 | {\r |
| 400 | *dest=0x01010101;\r |
| 401 | dest+=2;\r |
| 402 | }\r |
| 403 | \r |
| 404 | dest=(uint32 *)(XBuf+SCREEN_WIDTH*(12+4)+164+6+SCREEN_OFFS );\r |
| 405 | for(x=0;x<8;x++,dest+=2)\r |
| 406 | {\r |
| 407 | uint32 *da=dest+(SCREEN_WIDTH>>2);\r |
| 408 | \r |
| 409 | if(!((vsdip>>x)&1))\r |
| 410 | da+=(SCREEN_WIDTH>>2)*10;\r |
| 411 | for(y=4;y;y--,da+=SCREEN_WIDTH>>2)\r |
| 412 | *da=0;\r |
| 413 | }\r |
| 414 | }\r |
| 415 | \r |
| 416 | \r |
| 417 | SFORMAT FCEUVSUNI_STATEINFO[]={\r |
| 418 | { &vsdip, 1, "vsdp"},\r |
| 419 | { &coinon, 1, "vscn"},\r |
| 420 | { &VSindex, 1, "vsin"},\r |
| 421 | { 0}\r |
| 422 | };\r |