| 1 | /* FCE Ultra - NES/Famicom Emulator\r |
| 2 | *\r |
| 3 | * Copyright notice for this file:\r |
| 4 | * Copyright (C) 2006 CaH4e3\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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r |
| 19 | */\r |
| 20 | \r |
| 21 | #include "mapinc.h"\r |
| 22 | #include "mmc3.h"\r |
| 23 | #include "../ines.h"\r |
| 24 | \r |
| 25 | static bool is_BMCFK23CA;\r |
| 26 | static uint8 unromchr;\r |
| 27 | static uint32 dipswitch;\r |
| 28 | static uint8 *CHRRAM=NULL;\r |
| 29 | static uint32 CHRRAMSize;\r |
| 30 | \r |
| 31 | static void BMCFK23CCW(uint32 A, uint8 V)\r |
| 32 | {\r |
| 33 | if(EXPREGS[0]&0x40)\r |
| 34 | setchr8(EXPREGS[2]|unromchr);\r |
| 35 | else if(EXPREGS[0]&0x20) {\r |
| 36 | setchr1r(0x10, A, V);\r |
| 37 | }\r |
| 38 | else\r |
| 39 | {\r |
| 40 | uint16 base=(EXPREGS[2]&0x7F)<<3;\r |
| 41 | if(EXPREGS[3]&2)\r |
| 42 | {\r |
| 43 | int cbase=(MMC3_cmd&0x80)<<5;\r |
| 44 | setchr1(A,V|base);\r |
| 45 | setchr1(0x0000^cbase,DRegBuf[0]|base);\r |
| 46 | setchr1(0x0400^cbase,EXPREGS[6]|base);\r |
| 47 | setchr1(0x0800^cbase,DRegBuf[1]|base);\r |
| 48 | setchr1(0x0c00^cbase,EXPREGS[7]|base);\r |
| 49 | }\r |
| 50 | else\r |
| 51 | setchr1(A,V|base);\r |
| 52 | }\r |
| 53 | }\r |
| 54 | \r |
| 55 | //some games are wired differently, and this will need to be changed.\r |
| 56 | //all the WXN games require prg_bonus = 1, and cah4e3's multicarts require prg_bonus = 0\r |
| 57 | //we'll populate this from a game database\r |
| 58 | static int prg_bonus;\r |
| 59 | static int prg_mask;\r |
| 60 | \r |
| 61 | //prg_bonus = 0\r |
| 62 | //4-in-1 (FK23C8021)[p1][!].nes\r |
| 63 | //4-in-1 (FK23C8033)[p1][!].nes\r |
| 64 | //4-in-1 (FK23C8043)[p1][!].nes\r |
| 65 | //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes\r |
| 66 | \r |
| 67 | //prg_bonus = 1\r |
| 68 | //[m176]大富翁2-上海大亨.wxn.nes\r |
| 69 | //[m176]宠物翡翠.fix.nes\r |
| 70 | //[m176]格兰帝亚.wxn.nes\r |
| 71 | //[m176]梦幻之星.wxn.nes\r |
| 72 | //[m176]水浒神兽.fix.nes\r |
| 73 | //[m176]西楚霸王.fix.nes\r |
| 74 | //[m176]超级大富翁.wxn.nes\r |
| 75 | //[m176]雄霸天下.wxn.nes\r |
| 76 | \r |
| 77 | //works as-is under virtuanes m176\r |
| 78 | //[m176]三侠五义.wxn.nes\r |
| 79 | //[m176]口袋金.fix.nes\r |
| 80 | //[m176]爆笑三国.fix.nes\r |
| 81 | \r |
| 82 | //needs other tweaks\r |
| 83 | //[m176]三国忠烈传.wxn.nes\r |
| 84 | //[m176]破釜沉舟.fix.nes\r |
| 85 | \r |
| 86 | //PRG wrapper\r |
| 87 | static void BMCFK23CPW(uint32 A, uint8 V)\r |
| 88 | {\r |
| 89 | uint32 bank = (EXPREGS[1] & 0x1F);\r |
| 90 | uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);\r |
| 91 | uint32 block = (EXPREGS[1] & 0x60) | hiblock;\r |
| 92 | uint32 extra = (EXPREGS[3] & 2);\r |
| 93 | \r |
| 94 | if((EXPREGS[0]&7)==4)\r |
| 95 | setprg32(0x8000,EXPREGS[1]>>1);\r |
| 96 | else if ((EXPREGS[0]&7)==3)\r |
| 97 | {\r |
| 98 | setprg16(0x8000,EXPREGS[1]);\r |
| 99 | setprg16(0xC000,EXPREGS[1]);\r |
| 100 | } \r |
| 101 | else\r |
| 102 | { \r |
| 103 | if(EXPREGS[0]&3)\r |
| 104 | {\r |
| 105 | uint32 blocksize = (6)-(EXPREGS[0]&3);\r |
| 106 | uint32 mask = (1<<blocksize)-1;\r |
| 107 | V &= mask;\r |
| 108 | //V &= 63; //? is this a good idea?\r |
| 109 | V |= (EXPREGS[1]<<1);\r |
| 110 | setprg8(A,V);\r |
| 111 | }\r |
| 112 | else\r |
| 113 | setprg8(A,V & prg_mask);\r |
| 114 | \r |
| 115 | if(EXPREGS[3]&2)\r |
| 116 | {\r |
| 117 | setprg8(0xC000,EXPREGS[4]);\r |
| 118 | setprg8(0xE000,EXPREGS[5]);\r |
| 119 | }\r |
| 120 | }\r |
| 121 | setprg8r(0x10,0x6000,A001B&3);\r |
| 122 | }\r |
| 123 | \r |
| 124 | //PRG handler ($8000-$FFFF)\r |
| 125 | static DECLFW(BMCFK23CHiWrite)\r |
| 126 | {\r |
| 127 | if(EXPREGS[0]&0x40)\r |
| 128 | {\r |
| 129 | if(EXPREGS[0]&0x30)\r |
| 130 | unromchr=0;\r |
| 131 | else\r |
| 132 | {\r |
| 133 | unromchr=V&3;\r |
| 134 | FixMMC3CHR(MMC3_cmd);\r |
| 135 | }\r |
| 136 | }\r |
| 137 | else\r |
| 138 | {\r |
| 139 | if((A==0x8001)&&(EXPREGS[3]&2&&MMC3_cmd&8))\r |
| 140 | {\r |
| 141 | EXPREGS[4|(MMC3_cmd&3)]=V;\r |
| 142 | FixMMC3PRG(MMC3_cmd);\r |
| 143 | FixMMC3CHR(MMC3_cmd);\r |
| 144 | }\r |
| 145 | else\r |
| 146 | if(A<0xC000) {\r |
| 147 | if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions\r |
| 148 | // check if it not interfer with other dumps\r |
| 149 | if((A==0x8000)&&(V==0x46))\r |
| 150 | V=0x47;\r |
| 151 | else if((A==0x8000)&&(V==0x47))\r |
| 152 | V=0x46;\r |
| 153 | }\r |
| 154 | MMC3_CMDWrite(A,V);\r |
| 155 | FixMMC3PRG(MMC3_cmd);\r |
| 156 | }\r |
| 157 | else\r |
| 158 | MMC3_IRQWrite(A,V);\r |
| 159 | }\r |
| 160 | }\r |
| 161 | \r |
| 162 | //EXP handler ($5000-$5FFF)\r |
| 163 | static DECLFW(BMCFK23CWrite)\r |
| 164 | {\r |
| 165 | if(A&(1<<(dipswitch+4)))\r |
| 166 | {\r |
| 167 | //printf("+ ");\r |
| 168 | EXPREGS[A&3]=V;\r |
| 169 | \r |
| 170 | bool remap = false;\r |
| 171 | \r |
| 172 | //sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this. \r |
| 173 | //if not, 0x24 is a value that is known to work\r |
| 174 | //however, the low 4 bits are known to control the mapping mode, so 0x20 is more likely to be the immediate remap flag\r |
| 175 | remap |= ((EXPREGS[0]&0xF0)==0x20); \r |
| 176 | \r |
| 177 | //this is an actual mapping reg. i think reg0 controls what happens when reg1 is written. anyway, we have to immediately remap these\r |
| 178 | remap |= (A&3)==1; \r |
| 179 | //this too.\r |
| 180 | remap |= (A&3)==2; \r |
| 181 | \r |
| 182 | if(remap)\r |
| 183 | {\r |
| 184 | FixMMC3PRG(MMC3_cmd);\r |
| 185 | FixMMC3CHR(MMC3_cmd);\r |
| 186 | }\r |
| 187 | }\r |
| 188 | \r |
| 189 | if(is_BMCFK23CA)\r |
| 190 | {\r |
| 191 | if(EXPREGS[3]&2)\r |
| 192 | EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper)\r |
| 193 | }\r |
| 194 | \r |
| 195 | //printf("%04X = $%02X\n",A,V);\r |
| 196 | //printf("%02X %02X %02X %02X\n",EXPREGS[0],EXPREGS[1],EXPREGS[2],EXPREGS[3]);\r |
| 197 | }\r |
| 198 | \r |
| 199 | static void BMCFK23CReset(void)\r |
| 200 | {\r |
| 201 | //NOT NECESSARY ANYMORE\r |
| 202 | //this little hack makes sure that we try all the dip switch settings eventually, if we reset enough\r |
| 203 | // dipswitch++;\r |
| 204 | // dipswitch&=7;\r |
| 205 | //printf("BMCFK23C dipswitch set to %d\n",dipswitch);\r |
| 206 | \r |
| 207 | EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;\r |
| 208 | EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;\r |
| 209 | MMC3RegReset();\r |
| 210 | FixMMC3PRG(MMC3_cmd);\r |
| 211 | FixMMC3CHR(MMC3_cmd);\r |
| 212 | }\r |
| 213 | \r |
| 214 | static void BMCFK23CPower(void)\r |
| 215 | {\r |
| 216 | dipswitch = 0;\r |
| 217 | GenMMC3Power();\r |
| 218 | EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;\r |
| 219 | EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;\r |
| 220 | GenMMC3Power();\r |
| 221 | SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);\r |
| 222 | SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);\r |
| 223 | FixMMC3PRG(MMC3_cmd);\r |
| 224 | FixMMC3CHR(MMC3_cmd);\r |
| 225 | }\r |
| 226 | \r |
| 227 | static void BMCFK23CAPower(void)\r |
| 228 | {\r |
| 229 | GenMMC3Power();\r |
| 230 | dipswitch = 0;\r |
| 231 | EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;\r |
| 232 | EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;\r |
| 233 | SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);\r |
| 234 | SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);\r |
| 235 | FixMMC3PRG(MMC3_cmd);\r |
| 236 | FixMMC3CHR(MMC3_cmd);\r |
| 237 | }\r |
| 238 | \r |
| 239 | static void BMCFK23CAClose(void)\r |
| 240 | {\r |
| 241 | if(CHRRAM)\r |
| 242 | FCEU_gfree(CHRRAM);\r |
| 243 | CHRRAM=NULL;\r |
| 244 | }\r |
| 245 | \r |
| 246 | void BMCFK23C_Init(CartInfo *info)\r |
| 247 | {\r |
| 248 | is_BMCFK23CA = false;\r |
| 249 | \r |
| 250 | GenMMC3_Init(info, 512, 256, 8, 0);\r |
| 251 | cwrap=BMCFK23CCW;\r |
| 252 | pwrap=BMCFK23CPW;\r |
| 253 | info->Power=BMCFK23CPower;\r |
| 254 | info->Reset=BMCFK23CReset;\r |
| 255 | AddExState(EXPREGS, 8, 0, "EXPR");\r |
| 256 | AddExState(&unromchr, 1, 0, "UNCHR");\r |
| 257 | AddExState(&dipswitch, 1, 0, "DIPSW");\r |
| 258 | \r |
| 259 | prg_bonus = 1;\r |
| 260 | if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end())\r |
| 261 | prg_bonus = atoi(MasterRomInfoParams["bonus"].c_str());\r |
| 262 | \r |
| 263 | prg_mask = 0x7F>>(prg_bonus);\r |
| 264 | }\r |
| 265 | \r |
| 266 | void BMCFK23CA_Init(CartInfo *info)\r |
| 267 | {\r |
| 268 | is_BMCFK23CA = true;\r |
| 269 | \r |
| 270 | GenMMC3_Init(info, 512, 256, 8, 0);\r |
| 271 | cwrap=BMCFK23CCW;\r |
| 272 | pwrap=BMCFK23CPW;\r |
| 273 | info->Power=BMCFK23CAPower;\r |
| 274 | info->Reset=BMCFK23CReset;\r |
| 275 | info->Close=BMCFK23CAClose;\r |
| 276 | \r |
| 277 | CHRRAMSize=8192;\r |
| 278 | CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize);\r |
| 279 | SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1);\r |
| 280 | AddExState(CHRRAM, CHRRAMSize, 0, "CRAM");\r |
| 281 | \r |
| 282 | AddExState(EXPREGS, 8, 0, "EXPR");\r |
| 283 | AddExState(&unromchr, 1, 0, "UNCHR");\r |
| 284 | AddExState(&dipswitch, 1, 0, "DIPSW");\r |
| 285 | \r |
| 286 | prg_bonus = 1;\r |
| 287 | if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end())\r |
| 288 | prg_bonus = atoi(MasterRomInfoParams["bonus"].c_str());\r |
| 289 | prg_mask = 0x7F>>(prg_bonus);\r |
| 290 | }\r |