| 1 | /* FCE Ultra - NES/Famicom Emulator\r |
| 2 | *\r |
| 3 | * Copyright notice for this file:\r |
| 4 | * Copyright (C) 2007-2010 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 | * OneBus system\r |
| 21 | * Street Dance (Dance pad) (Unl)\r |
| 22 | * 101-in-1 Arcade Action II\r |
| 23 | * DreamGEAR 75-in-1\r |
| 24 | */\r |
| 25 | \r |
| 26 | #include "mapinc.h"\r |
| 27 | \r |
| 28 | static uint8 isDance;\r |
| 29 | static uint8 regs[16],regc[6];\r |
| 30 | static uint8 IRQCount,IRQLatch,IRQa, IRQReload, pcm_enable = 0, pcm_irq = 0;\r |
| 31 | static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xF6;\r |
| 32 | static writefunc old4011write, old4012write, old4013write, old4015write;\r |
| 33 | static readfunc old4015read;\r |
| 34 | \r |
| 35 | static SFORMAT StateRegs[]=\r |
| 36 | {\r |
| 37 | {regc, 6, "REGC"},\r |
| 38 | {regs, 16, "REGS"},\r |
| 39 | {&IRQReload, 1, "IRQR"},\r |
| 40 | {&IRQCount, 1, "IRQC"},\r |
| 41 | {&IRQLatch, 1, "IRQL"},\r |
| 42 | {&IRQa, 1, "IRQA"},\r |
| 43 | {&pcm_enable, 1, "PCME"},\r |
| 44 | {&pcm_irq, 1, "PCMIRQ"},\r |
| 45 | {&pcm_addr, 2, "PCMADDR"},\r |
| 46 | {&pcm_size, 2, "PCMSIZE"},\r |
| 47 | {&pcm_latch, 2, "PCMLATCH"},\r |
| 48 | {&pcm_clock, 2, "PCMCLOCK"},\r |
| 49 | {0}\r |
| 50 | };\r |
| 51 | \r |
| 52 | static void Sync(void)\r |
| 53 | {\r |
| 54 | uint16 cswap = (regs[0xf] & 0x80) << 5;\r |
| 55 | uint16 pswap = (regs[0xd]&1)?((regs[0xf] & 0x40) << 8):0;\r |
| 56 | uint16 pbase = (regs[0]&0xf0)<<4;\r |
| 57 | uint16 cbase = (((regs[0]&0x0f)<<8)|(regs[0xc]<<1)|((regs[0xd]&0xf8)>>3))<<3;\r |
| 58 | uint16 pmask = 0x3f>>(regs[0xb]&0xf);\r |
| 59 | \r |
| 60 | setchr1(cswap^0x0000,cbase|(regc[0]&(~1)));\r |
| 61 | setchr1(cswap^0x0400,cbase|(regc[0]|1));\r |
| 62 | setchr1(cswap^0x0800,cbase|(regc[1]&(-1)));\r |
| 63 | setchr1(cswap^0x0c00,cbase|(regc[1]|1));\r |
| 64 | setchr1(cswap^0x1000,cbase|(regc[2]));\r |
| 65 | setchr1(cswap^0x1400,cbase|(regc[3]));\r |
| 66 | setchr1(cswap^0x1800,cbase|(regc[4]));\r |
| 67 | setchr1(cswap^0x1c00,cbase|(regc[5]));\r |
| 68 | \r |
| 69 | if(regs[0xd]&2)\r |
| 70 | {\r |
| 71 | setprg8(pswap^0x8000, pbase|(regs[0x7]&pmask)|(regs[0xa]&(~pmask)));\r |
| 72 | setprg8( 0xA000, pbase|(regs[0x8]&pmask)|(regs[0xa]&(~pmask)));\r |
| 73 | setprg8(pswap^0xC000, pbase|(regs[0x9]&pmask)|(regs[0xa]&(~pmask)));\r |
| 74 | setprg8( 0xE000, pbase|regs[0xa]);\r |
| 75 | }\r |
| 76 | else\r |
| 77 | {\r |
| 78 | setprg8(pswap^0x8000, pbase|(regs[0x7]&pmask)|(regs[0xa]&(~pmask)));\r |
| 79 | setprg8( 0xA000, pbase|(regs[0x8]&pmask)|(regs[0xa]&(~pmask)));\r |
| 80 | setprg8(pswap^0xC000, pbase|((~1)&pmask)|(regs[0xa]&(~pmask)));\r |
| 81 | setprg8( 0xE000, pbase|((~0)&pmask)|(regs[0xa]&(~pmask)));\r |
| 82 | }\r |
| 83 | \r |
| 84 | setmirror(regs[0xe]);\r |
| 85 | }\r |
| 86 | \r |
| 87 | static DECLFW(UNLOneBusWrite20XX)\r |
| 88 | {\r |
| 89 | // FCEU_printf("PPU %04x:%04x\n",A,V);\r |
| 90 | if(A == 0x201A)\r |
| 91 | regs[0xd] = V;\r |
| 92 | else if(A == 0x2018)\r |
| 93 | regs[0xc] = V;\r |
| 94 | Sync();\r |
| 95 | }\r |
| 96 | \r |
| 97 | static DECLFW(UNLOneBusWriteExp)\r |
| 98 | {\r |
| 99 | // FCEU_printf("EXP %04x:%04x\n",A,V);\r |
| 100 | // switch(A & 0x0F)\r |
| 101 | // {\r |
| 102 | // case 2: pcm_latch = pcm_clock; FCEU_printf("write %04x:%04x\n",A,V); break;\r |
| 103 | // case 3: pcm_irqa = 0; X6502_IRQEnd(FCEU_IQEXT); pcm_irq = 0; FCEU_printf("write %04x:%04x\n",A,V); break;\r |
| 104 | // case 4: pcm_irqa = 1; FCEU_printf("write %04x:%04x\n",A,V); break;\r |
| 105 | // default:\r |
| 106 | regs[A & 0x0F] = V;\r |
| 107 | Sync();\r |
| 108 | // }\r |
| 109 | }\r |
| 110 | \r |
| 111 | static DECLFW(UNLOneBusWriteDebug)\r |
| 112 | {\r |
| 113 | // FCEU_printf("write %04x:%04x\n",A,V);\r |
| 114 | }\r |
| 115 | \r |
| 116 | static DECLFW(UNLOneBusWriteMMC)\r |
| 117 | {\r |
| 118 | // FCEU_printf("MMC %04x:%04x\n",A,V);\r |
| 119 | switch(A&0xE001)\r |
| 120 | {\r |
| 121 | case 0x8000: regs[0xf] = V; Sync(); break;\r |
| 122 | case 0x8001:\r |
| 123 | {\r |
| 124 | uint8 mask = 0xff, mmc3cmd = regs[0xf]&7;\r |
| 125 | switch(mmc3cmd)\r |
| 126 | {\r |
| 127 | case 0:\r |
| 128 | case 1:\r |
| 129 | case 2:\r |
| 130 | case 3:\r |
| 131 | case 4:\r |
| 132 | case 5:\r |
| 133 | if(regs[0xd]&4)\r |
| 134 | mask = 0x0f;\r |
| 135 | else\r |
| 136 | mask >>= ((regs[0xb]&0xf0)>>4);\r |
| 137 | regc[mmc3cmd] = V&mask;\r |
| 138 | break;\r |
| 139 | case 6:\r |
| 140 | case 7:\r |
| 141 | mask = (mask&0x3f)>>(regs[0xb]&0xf);\r |
| 142 | regs[mmc3cmd+1] = (regs[mmc3cmd+1]&(~mask))|(V&mask);\r |
| 143 | break;\r |
| 144 | }\r |
| 145 | \r |
| 146 | Sync();\r |
| 147 | break;\r |
| 148 | }\r |
| 149 | case 0xA000: regs[0xe] = (V & 1)^1; Sync(); break;\r |
| 150 | case 0xC000: IRQLatch = V&0xfe; break;\r |
| 151 | case 0xC001: IRQReload = 1; break;\r |
| 152 | case 0xE000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break;\r |
| 153 | case 0xE001: IRQa = 1; break;\r |
| 154 | }\r |
| 155 | }\r |
| 156 | \r |
| 157 | static void UNLOneBusIRQHook(void)\r |
| 158 | {\r |
| 159 | int count = IRQCount;\r |
| 160 | if(!count || IRQReload)\r |
| 161 | {\r |
| 162 | IRQCount = IRQLatch;\r |
| 163 | IRQReload = 0;\r |
| 164 | }\r |
| 165 | else\r |
| 166 | IRQCount--;\r |
| 167 | if(count && !IRQCount)\r |
| 168 | {\r |
| 169 | if(IRQa)\r |
| 170 | X6502_IRQBegin(FCEU_IQEXT);\r |
| 171 | }\r |
| 172 | }\r |
| 173 | \r |
| 174 | static DECLFW(UNLOneBusWriteAPU2)\r |
| 175 | {\r |
| 176 | // FCEU_printf("APU2 %04x:%04x\n",A,V);\r |
| 177 | CartBW(A&0xffdf,V);\r |
| 178 | }\r |
| 179 | \r |
| 180 | static DECLFW(UNLOneBusWrite4012)\r |
| 181 | {\r |
| 182 | // FCEU_printf("write %04x:%04x\n",A,V);\r |
| 183 | pcm_addr = V << 6;\r |
| 184 | old4012write(A,V);\r |
| 185 | }\r |
| 186 | \r |
| 187 | static DECLFW(UNLOneBusWrite4013)\r |
| 188 | {\r |
| 189 | // FCEU_printf("write %04x:%04x\n",A,V);\r |
| 190 | pcm_size = (V << 4) + 1;\r |
| 191 | old4013write(A,V);\r |
| 192 | }\r |
| 193 | \r |
| 194 | static DECLFW(UNLOneBusWrite4015)\r |
| 195 | {\r |
| 196 | // FCEU_printf("write %04x:%04x\n",A,V);\r |
| 197 | pcm_enable = V&0x10;\r |
| 198 | if(pcm_irq)\r |
| 199 | {\r |
| 200 | X6502_IRQEnd(FCEU_IQEXT);\r |
| 201 | pcm_irq = 0;\r |
| 202 | }\r |
| 203 | if(pcm_enable)\r |
| 204 | pcm_latch = pcm_clock;\r |
| 205 | old4015write(A,V&0xEF);\r |
| 206 | }\r |
| 207 | \r |
| 208 | static DECLFR(UNLOneBusRead4015)\r |
| 209 | {\r |
| 210 | uint8 result = (old4015read(A) & 0x7F)|pcm_irq;\r |
| 211 | // FCEU_printf("read %04x, %02x\n",A,result);\r |
| 212 | return result;\r |
| 213 | }\r |
| 214 | \r |
| 215 | static void UNLOneBusCpuHook(int a)\r |
| 216 | {\r |
| 217 | if(pcm_enable)\r |
| 218 | {\r |
| 219 | pcm_latch-=a;\r |
| 220 | if(pcm_latch<=0)\r |
| 221 | {\r |
| 222 | pcm_latch+=pcm_clock;\r |
| 223 | pcm_size--;\r |
| 224 | if(pcm_size<0)\r |
| 225 | {\r |
| 226 | pcm_irq = 0x80;\r |
| 227 | pcm_enable = 0;\r |
| 228 | X6502_IRQBegin(FCEU_IQEXT);\r |
| 229 | }\r |
| 230 | else\r |
| 231 | {\r |
| 232 | uint8 raw_pcm = ARead[pcm_addr](pcm_addr) >> 1;\r |
| 233 | old4011write(0x4011,raw_pcm);\r |
| 234 | pcm_addr++;\r |
| 235 | pcm_addr&=0x7FFF;\r |
| 236 | }\r |
| 237 | }\r |
| 238 | }\r |
| 239 | }\r |
| 240 | \r |
| 241 | static void UNLOneBusPower(void)\r |
| 242 | {\r |
| 243 | IRQCount=IRQLatch=IRQa==0;\r |
| 244 | regs[0]=regs[1]=regs[1]=regs[2]=regs[3]=regs[4]=regs[5]=regs[6]=0;\r |
| 245 | regs[7]=regs[8]=regs[11]=regs[12]=regs[13]=regs[14]=regs[15]=0;\r |
| 246 | regs[0x09]=0x3E;\r |
| 247 | regs[0x0A]=0x3F;\r |
| 248 | \r |
| 249 | SetupCartCHRMapping(0,PRGptr[0],4096 * 1024,0);\r |
| 250 | \r |
| 251 | if(isDance) // quick workaround, TODO: figure out how it works together\r |
| 252 | {\r |
| 253 | old4015read=GetReadHandler(0x4015);\r |
| 254 | SetReadHandler(0x4015,0x4015,UNLOneBusRead4015);\r |
| 255 | old4011write=GetWriteHandler(0x4011);\r |
| 256 | old4012write=GetWriteHandler(0x4012);\r |
| 257 | SetWriteHandler(0x4012,0x4012,UNLOneBusWrite4012);\r |
| 258 | old4013write=GetWriteHandler(0x4013);\r |
| 259 | SetWriteHandler(0x4013,0x4013,UNLOneBusWrite4013);\r |
| 260 | old4015write=GetWriteHandler(0x4015);\r |
| 261 | SetWriteHandler(0x4015,0x4015,UNLOneBusWrite4015);\r |
| 262 | }\r |
| 263 | \r |
| 264 | SetReadHandler(0x8000,0xFFFF,CartBR);\r |
| 265 | SetWriteHandler(0x2009,0x2fff,UNLOneBusWrite20XX);\r |
| 266 | // SetWriteHandler(0x4020,0xffff,UNLOneBusWriteDebug);\r |
| 267 | // SetWriteHandler(0x4020,0x4040,UNLOneBusWriteAPU2);\r |
| 268 | SetWriteHandler(0x4100,0x410f,UNLOneBusWriteExp);\r |
| 269 | SetWriteHandler(0x8000,0xefff,UNLOneBusWriteMMC);\r |
| 270 | Sync();\r |
| 271 | }\r |
| 272 | \r |
| 273 | static void UNLOneBusReset(void)\r |
| 274 | {\r |
| 275 | IRQCount=IRQLatch=IRQa=0;\r |
| 276 | regs[0]=regs[1]=regs[1]=regs[2]=regs[3]=regs[4]=regs[5]=regs[6]=0;\r |
| 277 | regs[7]=regs[8]=regs[11]=regs[12]=regs[13]=regs[14]=regs[15]=0;\r |
| 278 | regs[0x09]=0x3E;\r |
| 279 | regs[0x0A]=0x3F;\r |
| 280 | Sync();\r |
| 281 | }\r |
| 282 | \r |
| 283 | static void StateRestore(int version)\r |
| 284 | {\r |
| 285 | Sync();\r |
| 286 | }\r |
| 287 | \r |
| 288 | void UNLOneBus_Init(CartInfo *info)\r |
| 289 | {\r |
| 290 | isDance = 0;\r |
| 291 | info->Power=UNLOneBusPower;\r |
| 292 | info->Reset=UNLOneBusReset;\r |
| 293 | GameHBIRQHook=UNLOneBusIRQHook;\r |
| 294 | // MapIRQHook=UNLOneBusCpuHook;\r |
| 295 | GameStateRestore=StateRestore;\r |
| 296 | AddExState(&StateRegs, ~0, 0, 0);\r |
| 297 | }\r |
| 298 | \r |
| 299 | void UNLDANCE_Init(CartInfo *info)\r |
| 300 | {\r |
| 301 | isDance = 1;\r |
| 302 | info->Power=UNLOneBusPower;\r |
| 303 | info->Reset=UNLOneBusReset;\r |
| 304 | GameHBIRQHook=UNLOneBusIRQHook;\r |
| 305 | MapIRQHook=UNLOneBusCpuHook;\r |
| 306 | GameStateRestore=StateRestore;\r |
| 307 | AddExState(&StateRegs, ~0, 0, 0);\r |
| 308 | }\r |