mapvrc.c
1 /* 2 ** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) 3 ** 4 ** 5 ** This program is free software; you can redistribute it and/or 6 ** modify it under the terms of version 2 of the GNU Library General 7 ** Public License as published by the Free Software Foundation. 8 ** 9 ** This program is distributed in the hope that it will be useful, 10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 ** Library General Public License for more details. To obtain a 13 ** copy of the GNU Library General Public License, write to the Free 14 ** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 15 ** 16 ** Any permitted reproduction of these routines, in whole or in part, 17 ** must bear this legend. 18 ** 19 ** 20 ** map_vrc.c 21 ** 22 ** VRC mapper interface 23 ** $Id: mapvrc.c,v 1.2 2001/04/27 14:37:11 neil Exp $ 24 */ 25 26 #include "noftypes.h" 27 #include "nes_mmc.h" 28 #include "nes.h" 29 #include "log.h" 30 31 #define VRC_VBANK(bank, value, high) \ 32 { \ 33 if ((high)) \ 34 highnybbles[(bank)] = (value) & 0x0F; \ 35 else \ 36 lownybbles[(bank)] = (value) & 0x0F; \ 37 mmc_bankvrom(1, (bank) << 10, (highnybbles[(bank)] << 4)+lownybbles[(bank)]); \ 38 } 39 40 static struct 41 { 42 int counter, enabled; 43 int latch, wait_state; 44 } irq; 45 46 static int select_c000 = 0; 47 static uint8 lownybbles[8]; 48 static uint8 highnybbles[8]; 49 50 static void vrc_init(void) 51 { 52 irq.counter = irq.enabled = 0; 53 irq.latch = irq.wait_state = 0; 54 } 55 56 static void map21_write(uint32 address, uint8 value) 57 { 58 switch (address) 59 { 60 case 0x8000: 61 if (select_c000) 62 mmc_bankrom(8, 0xC000,value); 63 else 64 mmc_bankrom(8, 0x8000,value); 65 break; 66 67 case 0x9000: 68 switch (value & 3) 69 { 70 case 0: 71 ppu_mirror(0, 1, 0, 1); /* vertical */ 72 break; 73 74 case 1: 75 ppu_mirror(0, 0, 1, 1); /* horizontal */ 76 break; 77 78 case 2: 79 ppu_mirror(0, 0, 0, 0); 80 break; 81 82 case 3: 83 ppu_mirror(1, 1, 1, 1); 84 break; 85 86 default: 87 break; 88 } 89 break; 90 case 0x9002: select_c000=(value&0x02)>>1; break; 91 case 0xA000: mmc_bankrom(8, 0xA000,value); break; 92 93 case 0xB000: VRC_VBANK(0,value,0); break; 94 case 0xB002: 95 case 0xB040: VRC_VBANK(0,value,1); break; 96 case 0xB001: 97 case 0xB004: 98 case 0xB080: VRC_VBANK(1,value,0); break; 99 case 0xB003: 100 case 0xB006: 101 case 0xB0C0: VRC_VBANK(1,value,1); break; 102 case 0xC000: VRC_VBANK(2,value,0); break; 103 case 0xC002: 104 case 0xC040: VRC_VBANK(2,value,1); break; 105 case 0xC001: 106 case 0xC004: 107 case 0xC080: VRC_VBANK(3,value,0); break; 108 case 0xC003: 109 case 0xC006: 110 case 0xC0C0: VRC_VBANK(3,value,1); break; 111 case 0xD000: VRC_VBANK(4,value,0); break; 112 case 0xD002: 113 case 0xD040: VRC_VBANK(4,value,1); break; 114 case 0xD001: 115 case 0xD004: 116 case 0xD080: VRC_VBANK(5,value,0); break; 117 case 0xD003: 118 case 0xD006: 119 case 0xD0C0: VRC_VBANK(5,value,1); break; 120 case 0xE000: VRC_VBANK(6,value,0); break; 121 case 0xE002: 122 case 0xE040: VRC_VBANK(6,value,1); break; 123 case 0xE001: 124 case 0xE004: 125 case 0xE080: VRC_VBANK(7,value,0); break; 126 case 0xE003: 127 case 0xE006: 128 case 0xE0C0: VRC_VBANK(7,value,1); break; 129 130 case 0xF000: 131 irq.latch &= 0xF0; 132 irq.latch |= (value & 0x0F); 133 break; 134 case 0xF002: 135 case 0xF040: 136 irq.latch &= 0x0F; 137 irq.latch |= ((value & 0x0F) << 4); 138 break; 139 case 0xF004: 140 case 0xF001: 141 case 0xF080: 142 irq.enabled = (value >> 1) & 0x01; 143 irq.wait_state = value & 0x01; 144 irq.counter = irq.latch; 145 break; 146 case 0xF006: 147 case 0xF003: 148 case 0xF0C0: 149 irq.enabled = irq.wait_state; 150 break; 151 152 default: 153 #ifdef NOFRENDO_DEBUG 154 log_printf("wrote $%02X to $%04X", value, address); 155 #endif 156 break; 157 } 158 } 159 160 static void map22_write(uint32 address, uint8 value) 161 { 162 int reg = address >> 12; 163 164 switch (reg) 165 { 166 case 0x8: 167 mmc_bankrom(8, 0x8000, value); 168 break; 169 170 case 0xA: 171 mmc_bankrom(8, 0xA000, value); 172 break; 173 174 case 0x9: 175 switch (value & 3) 176 { 177 case 0: 178 ppu_mirror(0, 1, 0, 1); /* vertical */ 179 break; 180 181 case 1: 182 ppu_mirror(0, 0, 1, 1); /* horizontal */ 183 break; 184 185 case 2: 186 ppu_mirror(1, 1, 1, 1); 187 break; 188 189 case 3: 190 ppu_mirror(0, 0, 0, 0); 191 break; 192 } 193 break; 194 195 case 0xB: 196 case 0xC: 197 case 0xD: 198 case 0xE: 199 { 200 int loc = (((reg - 0xB) << 1) + (address & 1)) << 10; 201 mmc_bankvrom(1, loc, value >> 1); 202 } 203 break; 204 205 default: 206 break; 207 } 208 } 209 210 static void map23_write(uint32 address, uint8 value) 211 { 212 switch (address) 213 { 214 case 0x8000: 215 case 0x8FFF: 216 mmc_bankrom(8, 0x8000, value); 217 break; 218 219 case 0xA000: 220 case 0xAFFF: 221 mmc_bankrom(8, 0xA000, value); 222 break; 223 224 case 0x9000: 225 case 0x9004: 226 case 0x9008: 227 switch(value & 3) 228 { 229 case 0: 230 ppu_mirror(0, 1, 0, 1); /* vertical */ 231 break; 232 233 case 1: 234 ppu_mirror(0, 0, 1, 1); /* horizontal */ 235 break; 236 237 case 2: 238 ppu_mirror(0, 0, 0, 0); 239 break; 240 241 case 3: 242 ppu_mirror(1, 1, 1, 1); 243 break; 244 } 245 break; 246 247 case 0xB000: VRC_VBANK(0,value,0); break; 248 case 0xB001: 249 case 0xB004: VRC_VBANK(0,value,1); break; 250 case 0xB002: 251 case 0xB008: VRC_VBANK(1,value,0); break; 252 case 0xB003: 253 case 0xB00C: VRC_VBANK(1,value,1); break; 254 case 0xC000: VRC_VBANK(2,value,0); break; 255 case 0xC001: 256 case 0xC004: VRC_VBANK(2,value,1); break; 257 case 0xC002: 258 case 0xC008: VRC_VBANK(3,value,0); break; 259 case 0xC003: 260 case 0xC00C: VRC_VBANK(3,value,1); break; 261 case 0xD000: VRC_VBANK(4,value,0); break; 262 case 0xD001: 263 case 0xD004: VRC_VBANK(4,value,1); break; 264 case 0xD002: 265 case 0xD008: VRC_VBANK(5,value,0); break; 266 case 0xD003: 267 case 0xD00C: VRC_VBANK(5,value,1); break; 268 case 0xE000: VRC_VBANK(6,value,0); break; 269 case 0xE001: 270 case 0xE004: VRC_VBANK(6,value,1); break; 271 case 0xE002: 272 case 0xE008: VRC_VBANK(7,value,0); break; 273 case 0xE003: 274 case 0xE00C: VRC_VBANK(7,value,1); break; 275 276 case 0xF000: 277 irq.latch &= 0xF0; 278 irq.latch |= (value & 0x0F); 279 break; 280 281 case 0xF004: 282 irq.latch &= 0x0F; 283 irq.latch |= ((value & 0x0F) << 4); 284 break; 285 286 case 0xF008: 287 irq.enabled = (value >> 1) & 0x01; 288 irq.wait_state = value & 0x01; 289 irq.counter = irq.latch; 290 break; 291 292 case 0xF00C: 293 irq.enabled = irq.wait_state; 294 break; 295 296 default: 297 #ifdef NOFRENDO_DEBUG 298 log_printf("wrote $%02X to $%04X",value,address); 299 #endif 300 break; 301 } 302 } 303 304 static void vrc_hblank(int vblank) 305 { 306 UNUSED(vblank); 307 308 if (irq.enabled) 309 { 310 if (256 == ++irq.counter) 311 { 312 irq.counter = irq.latch; 313 nes_irq(); 314 //irq.enabled = false; 315 irq.enabled = irq.wait_state; 316 } 317 } 318 } 319 320 321 322 static map_memwrite map21_memwrite[] = 323 { 324 { 0x8000, 0xFFFF, map21_write }, 325 { -1, -1, NULL } 326 }; 327 328 static map_memwrite map22_memwrite[] = 329 { 330 { 0x8000, 0xFFFF, map22_write }, 331 { -1, -1, NULL } 332 }; 333 334 static map_memwrite map23_memwrite[] = 335 { 336 { 0x8000, 0xFFFF, map23_write }, 337 { -1, -1, NULL } 338 }; 339 340 static void map21_getstate(SnssMapperBlock *state) 341 { 342 state->extraData.mapper21.irqCounter = irq.counter; 343 state->extraData.mapper21.irqCounterEnabled = irq.enabled; 344 } 345 346 static void map21_setstate(SnssMapperBlock *state) 347 { 348 irq.counter = state->extraData.mapper21.irqCounter; 349 irq.enabled = state->extraData.mapper21.irqCounterEnabled; 350 } 351 352 const mapintf_t map21_intf = 353 { 354 21, /* mapper number */ 355 "Konami VRC4 A", /* mapper name */ 356 vrc_init, /* init routine */ 357 NULL, /* vblank callback */ 358 vrc_hblank, /* hblank callback */ 359 map21_getstate, /* get state (snss) */ 360 map21_setstate, /* set state (snss) */ 361 NULL, /* memory read structure */ 362 map21_memwrite, /* memory write structure */ 363 NULL /* external sound device */ 364 }; 365 366 const mapintf_t map22_intf = 367 { 368 22, /* mapper number */ 369 "Konami VRC2 A", /* mapper name */ 370 vrc_init, /* init routine */ 371 NULL, /* vblank callback */ 372 NULL, /* hblank callback */ 373 NULL, /* get state (snss) */ 374 NULL, /* set state (snss) */ 375 NULL, /* memory read structure */ 376 map22_memwrite, /* memory write structure */ 377 NULL /* external sound device */ 378 }; 379 380 const mapintf_t map23_intf = 381 { 382 23, /* mapper number */ 383 "Konami VRC2 B", /* mapper name */ 384 vrc_init, /* init routine */ 385 NULL, /* vblank callback */ 386 vrc_hblank, /* hblank callback */ 387 NULL, /* get state (snss) */ 388 NULL, /* set state (snss) */ 389 NULL, /* memory read structure */ 390 map23_memwrite, /* memory write structure */ 391 NULL /* external sound device */ 392 }; 393 394 const mapintf_t map25_intf = 395 { 396 25, /* mapper number */ 397 "Konami VRC4 B", /* mapper name */ 398 NULL, /* init routine */ 399 NULL, /* vblank callback */ 400 vrc_hblank, /* hblank callback */ 401 NULL, /* get state (snss) */ 402 NULL, /* set state (snss) */ 403 NULL, /* memory read structure */ 404 map21_memwrite, /* memory write structure */ 405 NULL /* external sound device */ 406 }; 407 408 /* 409 ** $Log: mapvrc.c,v $ 410 ** Revision 1.2 2001/04/27 14:37:11 neil 411 ** wheeee 412 ** 413 ** Revision 1.1 2001/04/27 12:54:40 neil 414 ** blah 415 ** 416 ** Revision 1.1.1.1 2001/04/27 07:03:54 neil 417 ** initial 418 ** 419 ** Revision 1.1 2000/10/24 12:19:33 matt 420 ** changed directory structure 421 ** 422 ** Revision 1.10 2000/10/22 19:17:46 matt 423 ** mapper cleanups galore 424 ** 425 ** Revision 1.9 2000/10/22 15:03:14 matt 426 ** simplified mirroring 427 ** 428 ** Revision 1.8 2000/10/21 19:33:38 matt 429 ** many more cleanups 430 ** 431 ** Revision 1.7 2000/10/10 13:58:17 matt 432 ** stroustrup squeezing his way in the door 433 ** 434 ** Revision 1.6 2000/08/16 02:50:11 matt 435 ** random mapper cleanups 436 ** 437 ** Revision 1.5 2000/07/15 23:52:20 matt 438 ** rounded out a bunch more mapper interfaces 439 ** 440 ** Revision 1.4 2000/07/10 13:51:25 matt 441 ** using generic nes_irq() routine now 442 ** 443 ** Revision 1.3 2000/07/10 05:29:03 matt 444 ** cleaned up some mirroring issues 445 ** 446 ** Revision 1.2 2000/07/06 02:48:43 matt 447 ** clearly labelled structure members 448 ** 449 ** Revision 1.1 2000/07/06 01:01:56 matt 450 ** initial revision 451 ** 452 */